Repository: scionproto/scion
Pull request #3631 (2020-01-22 10:00:53)

Use snet.{UDP,SVC}Addr instead of snet.Addr everywhere


<!-- Reviewable:start -->
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/scionproto/scion/3631)
<!-- Reviewable:end -->



Patch:
diff --git a/go/cs/beaconing/handler.go b/go/cs/beaconing/handler.go
index 22539f255..713d37b3c 100644
--- a/go/cs/beaconing/handler.go
+++ b/go/cs/beaconing/handler.go
@@ -137,9 +137,9 @@ func (h *handler) buildBeacon(ifid common.IFIDType) (beacon.Beacon, *infra.Handl
 
 func (h *handler) getIFID() (common.IFIDType, addr.IA, error) {
 	var ia addr.IA
-	peer, ok := h.request.Peer.(*snet.Addr)
+	peer, ok := h.request.Peer.(*snet.UDPAddr)
 	if !ok {
-		return 0, ia, common.NewBasicError("Invalid peer address type, expected *snet.Addr", nil,
+		return 0, ia, common.NewBasicError("Invalid peer address type, expected *snet.UDPAddr", nil,
 			"peer", h.request.Peer, "type", common.TypeOf(h.request.Peer))
 	}
 	hopF, err := peer.Path.GetHopField(peer.Path.HopOff)
@@ -194,7 +194,7 @@ func (h *handler) validateASEntry(b beacon.Beacon) error {
 }
 
 func (h *handler) verifySegment(segment *seg.PathSegment) error {
-	snetPeer := h.request.Peer.(*snet.Addr)
+	snetPeer := h.request.Peer.(*snet.UDPAddr)
 	peerPath, err := snetPeer.GetPath()
 	if err != nil {
 		return common.NewBasicError("path error", err)
diff --git a/go/cs/handlers/segreg.go b/go/cs/handlers/segreg.go
index e6c3046a8..cc3c9ab4e 100644
--- a/go/cs/handlers/segreg.go
+++ b/go/cs/handlers/segreg.go
@@ -66,7 +66,7 @@ func (h *segRegHandler) Handle() *infra.HandlerResult {
 		metrics.Registrations.ResultsTotal(labels).Inc()
 		return infra.MetricsErrInternal
 	}
-	snetPeer := h.request.Peer.(*snet.Addr)
+	snetPeer := h.request.Peer.(*snet.UDPAddr)
 	labels.Type = classifySegs(logger, segReg)
 	labels.Src = snetPeer.IA
 	rw, ok := infra.ResponseWriterFromContext(ctx)
diff --git a/go/cs/handlers/segsync.go b/go/cs/handlers/segsync.go
index d61618fe7..5d0471465 100644
--- a/go/cs/handlers/segsync.go
+++ b/go/cs/handlers/segsync.go
@@ -66,7 +66,7 @@ func (h *syncHandler) Handle() *infra.HandlerResult {
 		metrics.Sync.Registrations(labels).Inc()
 		return infra.MetricsErrInternal
 	}
-	snetPeer := h.request.Peer.(*snet.Addr)
+	snetPeer := h.request.Peer.(*snet.UDPAddr)
 	labels.Src = snetPeer.IA
 	rw, ok := infra.ResponseWriterFromContext(ctx)
 	if !ok {
diff --git a/go/cs/keepalive/handler.go b/go/cs/keepalive/handler.go
index f9b735cb2..ced708541 100644
--- a/go/cs/keepalive/handler.go
+++ b/go/cs/keepalive/handler.go
@@ -120,10 +120,10 @@ func (h *handler) handle(logger log.Logger) (*infra.HandlerResult, error) {
 }
 
 func (h *handler) getIntfInfo() (common.IFIDType, *ifstate.Interface, error) {
-	peer, ok := h.request.Peer.(*snet.Addr)
+	peer, ok := h.request.Peer.(*snet.UDPAddr)
 	if !ok {
-		return 0, nil, common.NewBasicError("Invalid peer address type, expected *snet.Addr", nil,
-			"peer", h.request.Peer, "type", common.TypeOf(h.request.Peer))
+		return 0, nil, common.NewBasicError("Invalid peer address type, expected *snet.UDPAddr",
+			nil, "peer", h.request.Peer, "type", common.TypeOf(h.request.Peer))
 	}
 	hopF, err := peer.Path.GetHopField(peer.Path.HopOff)
 	if err != nil {
diff --git a/go/examples/pingpong/pingpong.go b/go/examples/pingpong/pingpong.go
index 7b89a7d4c..a921ed7db 100644
--- a/go/examples/pingpong/pingpong.go
+++ b/go/examples/pingpong/pingpong.go
@@ -56,7 +56,7 @@ const (
 )
 
 var (
-	local, remote snet.Addr
+	local, remote snet.UDPAddr
 	fileData      []byte
 
 	count = flag.Int("count", 0,
@@ -75,8 +75,8 @@ var (
 )
 
 func init() {
-	flag.Var((*snet.Addr)(&local), "local", "(Mandatory) address to listen on")
-	flag.Var((*snet.Addr)(&remote), "remote", "(Mandatory for clients) address to connect to")
+	flag.Var(&local, "local", "(Mandatory) address to listen on")
+	flag.Var(&remote, "remote", "(Mandatory for clients) address to connect to")
 }
 
 func main() {
@@ -109,8 +109,8 @@ func validateFlags() {
 		if remote.Host == nil {
 			LogFatal("Missing remote address")
 		}
-		if remote.Host.L4 == 0 {
-			LogFatal("Invalid remote port", "remote port", remote.Host.L4)
+		if remote.Host.Port == 0 {
+			LogFatal("Invalid remote port", "remote port", remote.Host.Port)
 		}
 	}
 	if local.Host == nil {
@@ -240,8 +240,8 @@ func (c *client) run() {
 	// IP address needs to be supplied explicitly. When supplied a local
 	// port of 0, Dial will assign a random free local port.
 
-	remoteUDP := snet.NewUDPAddr(remote.IA, remote.Path, remote.NextHop, remote.ToNetUDPAddr())
-	c.qsess, err = squic.Dial(network, local.ToNetUDPAddr(), remoteUDP, addr.SvcNone, nil)
+	remoteUDP := snet.NewUDPAddr(remote.IA, remote.Path, remote.NextHop, remote.Host)
+	c.qsess, err = squic.Dial(network, local.Host, remoteUDP, addr.SvcNone, nil)
 	if err != nil {
 		LogFatal("Unable to dial", "err", err)
 	}
@@ -361,7 +361,7 @@ func (s server) run() {
 	if err != nil {
 		LogFatal("Unable to initialize SCION network", "err", err)
 	}
-	qsock, err := squic.Listen(network, local.ToNetUDPAddr(), addr.SvcNone, nil)
+	qsock, err := squic.Listen(network, local.Host, addr.SvcNone, nil)
 	if err != nil {
 		LogFatal("Unable to listen", "err", err)
 	}
diff --git a/go/hidden_path_srv/internal/hpcfgreq/handler.go b/go/hidden_path_srv/internal/hpcfgreq/handler.go
index b85f2f0d3..7236d4f13 100644
--- a/go/hidden_path_srv/internal/hpcfgreq/handler.go
+++ b/go/hidden_path_srv/internal/hpcfgreq/handler.go
@@ -74,9 +74,9 @@ func (h *handler) handle(logger log.Logger) (*infra.HandlerResult, error) {
 	sendAck := messenger.SendAckHelper(ctx, rw)
 	logger.Debug("[hpCfgReqHandler] Received HPCfgReq", "src", h.request.Peer, "req", hpCfgReq)
 
-	snetPeer, ok := h.request.Peer.(*snet.Addr)
+	snetPeer, ok := h.request.Peer.(*snet.UDPAddr)
 	if !ok {
-		logger.Error("[hpCfgReqHandler] Invalid peer address type, expected *snet.Addr", nil,
+		logger.Error("[hpCfgReqHandler] Invalid peer address type, expected *snet.UDPAddr", nil,
 			"peer", h.request.Peer, "type", common.TypeOf(h.request.Peer))
 		sendAck(proto.Ack_ErrCode_reject, messenger.AckRejectFailedToParse)
 		return infra.MetricsErrInvalid, nil
diff --git a/go/hidden_path_srv/internal/hpsegreq/fetcher.go b/go/hidden_path_srv/internal/hpsegreq/fetcher.go
index 0119d18ff..e702c4d56 100644
--- a/go/hidden_path_srv/internal/hpsegreq/fetcher.go
+++ b/go/hidden_path_srv/internal/hpsegreq/fetcher.go
@@ -40,7 +40,7 @@ type Fetcher interface {
 	// In case of local HPS the segments are fetched from the database,
 	// otherwise segments are requested from a remote HPS
 	Fetch(ctx context.Context,
-		req *path_mgmt.HPSegReq, peer *snet.Addr) ([]*path_mgmt.HPSegRecs, error)
+		req *path_mgmt.HPSegReq, peer *snet.UDPAddr) ([]*path_mgmt.HPSegRecs, error)
 }
 
 var _ Fetcher = (*DefaultFetcher)(nil)
@@ -65,7 +65,7 @@ func NewDefaultFetcher(groupInfo *GroupInfo, msger infra.Messenger,
 
 // Fetch fetches the hidden path segments either from DB or from a remote HPS
 func (f *DefaultFetcher) Fetch(ctx context.Context,
-	req *path_mgmt.HPSegReq, peer *snet.Addr) ([]*path_mgmt.HPSegRecs, error) {
+	req *path_mgmt.HPSegReq, peer *snet.UDPAddr) ([]*path_mgmt.HPSegRecs, error) {
 
 	ids := make([]hiddenpath.GroupId, 0, len(req.GroupIds))
 	for _, rawId := range req.GroupIds {
@@ -138,7 +138,7 @@ func (f *DefaultFetcher) fetchRemote(ctx context.Context, ids []hiddenpath.Group
 		RawDstIA: endsAt.IAInt(),
 		GroupIds: rawIds,
 	}
-	addr := &snet.Addr{IA: remote, Host: addr.NewSVCUDPAppAddr(addr.SvcHPS)}
+	addr := snet.NewSVCAddr(remote, nil, nil, addr.SvcHPS)
 	reply, err := f.msger.GetHPSegs(ctx, req, addr, messenger.NextId())
 	if err != nil {
 		var recs = make([]*path_mgmt.HPSegRecs, 0, len(ids))
diff --git a/go/hidden_path_srv/internal/hpsegreq/handler.go b/go/hidden_path_srv/internal/hpsegreq/handler.go
index 46c6ac25b..e03f395ea 100644
--- a/go/hidden_path_srv/internal/hpsegreq/handler.go
+++ b/go/hidden_path_srv/internal/hpsegreq/handler.go
@@ -67,9 +67,9 @@ func (h *hpSegReqHandler) handle(logger log.Logger) (*infra.HandlerResult, error
 	sendAck := messenger.SendAckHelper(ctx, rw)
 	logger.Debug("[hpSegReqHandler] Received HPSegReq", "src", h.request.Peer, "req", hpSegReq)
 
-	snetPeer, ok := h.request.Peer.(*snet.Addr)
+	snetPeer, ok := h.request.Peer.(*snet.UDPAddr)
 	if !ok {
-		logger.Error("[hpSegReqHandler] Invalid peer address type, expected *snet.Addr", nil,
+		logger.Error("[hpSegReqHandler] Invalid peer address type, expected *snet.UDPAddr", nil,
 			"peer", h.request.Peer, "type", common.TypeOf(h.request.Peer))
 		sendAck(proto.Ack_ErrCode_reject, messenger.AckRejectFailedToParse)
 		return infra.MetricsErrInvalid, nil
diff --git a/go/hidden_path_srv/internal/hpsegreq/mock_hpsegreq/hpsegreq.go b/go/hidden_path_srv/internal/hpsegreq/mock_hpsegreq/hpsegreq.go
index 549094a44..fbeac5190 100644
--- a/go/hidden_path_srv/internal/hpsegreq/mock_hpsegreq/hpsegreq.go
+++ b/go/hidden_path_srv/internal/hpsegreq/mock_hpsegreq/hpsegreq.go
@@ -36,7 +36,7 @@ func (m *MockFetcher) EXPECT() *MockFetcherMockRecorder {
 }
 
 // Fetch mocks base method
-func (m *MockFetcher) Fetch(arg0 context.Context, arg1 *path_mgmt.HPSegReq, arg2 *snet.Addr) ([]*path_mgmt.HPSegRecs, error) {
+func (m *MockFetcher) Fetch(arg0 context.Context, arg1 *path_mgmt.HPSegReq, arg2 *snet.UDPAddr) ([]*path_mgmt.HPSegRecs, error) {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "Fetch", arg0, arg1, arg2)
 	ret0, _ := ret[0].([]*path_mgmt.HPSegRecs)
diff --git a/go/hidden_path_srv/internal/registration/handler.go b/go/hidden_path_srv/internal/registration/handler.go
index 4d11398f5..7e6a08b1d 100644
--- a/go/hidden_path_srv/internal/registration/handler.go
+++ b/go/hidden_path_srv/internal/registration/handler.go
@@ -83,27 +83,14 @@ func (h *hpSegRegHandler) handle(logger log.Logger) (*infra.HandlerResult, error
 	logger.Debug("[hpSegRegHandler] Received HPSegRecs", "src",
 		h.request.Peer, "data", hpSegReg.HPSegRecs)
 
-	snetPeer, ok := h.request.Peer.(*snet.Addr)
+	snetPeer, ok := h.request.Peer.(*snet.UDPAddr)
 	if !ok {
-		logger.Error("[hpSegRegHandler] Invalid peer address type, expected *snet.Addr", nil,
+		logger.Error("[hpSegRegHandler] Invalid peer address type, expected *snet.UDPAddr", nil,
 			"peer", h.request.Peer, "type", common.TypeOf(h.request.Peer))
 		sendAck(proto.Ack_ErrCode_reject, messenger.AckRejectFailedToParse)
 		return infra.MetricsErrInvalid, nil
 	}
-	peerPath, err := snetPeer.GetPath()
-	if err != nil {
-		logger.Error("[hpSegRegHandler] Failed to initialize path", "err", err)
-		sendAck(proto.Ack_ErrCode_reject, messenger.AckRejectFailedToParse)
-		return infra.MetricsErrInvalid, nil
-	}
-	svcToQuery := &snet.Addr{
-		IA:      snetPeer.IA,
-		Path:    peerPath.Path(),
-		NextHop: peerPath.OverlayNextHop(),
-		Host:    addr.NewSVCUDPAppAddr(addr.SvcBS),
-	}
-	err = h.validator.Validate(hpSegReg, snetPeer.IA)
-	if err != nil {
+	if err := h.validator.Validate(hpSegReg, snetPeer.IA); err != nil {
 		sendAck(proto.Ack_ErrCode_reject, err.Error())
 		return infra.MetricsErrInvalid, nil
 	}
@@ -111,7 +98,7 @@ func (h *hpSegRegHandler) handle(logger log.Logger) (*infra.HandlerResult, error
 		Segs:      hpSegReg.Recs,
 		HPGroupID: hiddenpath.IdFromMsg(hpSegReg.GroupId),
 	}
-	res := h.segHandler.Handle(ctx, segRecs, svcToQuery, nil)
+	res := h.segHandler.Handle(ctx, segRecs, snetPeer, nil)
 	// wait until processing is done.
 	<-res.FullReplyProcessed()
 	if err := res.Err(); err != nil {
diff --git a/go/integration/cert_req/main.go b/go/integration/cert_req/main.go
index b861df1df..a729e9efe 100644
--- a/go/integration/cert_req/main.go
+++ b/go/integration/cert_req/main.go
@@ -74,7 +74,7 @@ func (c client) run() int {
 	network := integration.InitNetwork()
 	var err error
 	c.conn, err = network.Listen(context.Background(), "udp",
-		integration.Local.ToNetUDPAddr(), addr.SvcNone)
+		integration.Local.Host, addr.SvcNone)
 	if err != nil {
 		integration.LogFatal("Unable to listen", "err", err)
 	}
diff --git a/go/integration/common.go b/go/integration/common.go
index e677c3a03..817f7bffe 100644
--- a/go/integration/common.go
+++ b/go/integration/common.go
@@ -39,7 +39,7 @@ const (
 )
 
 var (
-	Local    snet.Addr
+	Local    snet.UDPAddr
 	Mode     string
 	sdSocket string
 	Attempts int
@@ -51,7 +51,7 @@ func Setup() {
 }
 
 func addFlags() {
-	flag.Var((*snet.Addr)(&Local), "local", "(Mandatory) address to listen on")
+	flag.Var((*snet.UDPAddr)(&Local), "local", "(Mandatory) address to listen on")
 	flag.StringVar(&Mode, "mode", ModeClient, "Run in "+ModeClient+" or "+ModeServer+" mode")
 	flag.StringVar(&sdSocket, "sciond", "", "Path to sciond socket")
 	flag.IntVar(&Attempts, "attempts", 1, "Number of attempts before giving up")
diff --git a/go/integration/end2end/main.go b/go/integration/end2end/main.go
index 668fc1821..532d2b83b 100644
--- a/go/integration/end2end/main.go
+++ b/go/integration/end2end/main.go
@@ -46,7 +46,7 @@ const (
 )
 
 var (
-	remote  snet.Addr
+	remote  snet.UDPAddr
 	timeout = &util.DurWrap{Duration: 2 * time.Second}
 )
 
@@ -75,7 +75,7 @@ func realMain() int {
 }
 
 func addFlags() {
-	flag.Var((*snet.Addr)(&remote), "remote", "(Mandatory for clients) address to connect to")
+	flag.Var(&remote, "remote", "(Mandatory for clients) address to connect to")
 	flag.Var(timeout, "timeout", "The timeout for each attempt")
 }
 
@@ -84,8 +84,8 @@ func validateFlags() {
 		if remote.Host == nil {
 			integration.LogFatal("Missing remote address")
 		}
-		if remote.Host.L4 == 0 {
-			integration.LogFatal("Invalid remote port", "remote port", remote.Host.L4)
+		if remote.Host.Port == 0 {
+			integration.LogFatal("Invalid remote port", "remote port", remote.Host.Port)
 		}
 		if timeout.Duration == 0 {
 			integration.LogFatal("Invalid timeout provided", "timeout", timeout)
@@ -104,7 +104,7 @@ func (s server) run() {
 		),
 	}
 	conn, port, err := connFactory.Register(context.Background(), integration.Local.IA,
-		integration.Local.ToNetUDPAddr(), addr.SvcNone)
+		integration.Local.Host, addr.SvcNone)
 	if err != nil {
 		integration.LogFatal("Error listening", "err", err)
 	}
@@ -161,12 +161,12 @@ func (c client) run() int {
 
 	var err error
 	c.conn, c.port, err = connFactory.Register(context.Background(), integration.Local.IA,
-		integration.Local.ToNetUDPAddr(), addr.SvcNone)
+		integration.Local.Host, addr.SvcNone)
 	if err != nil {
 		integration.LogFatal("Unable to listen", "err", err)
 	}
 	log.Debug("Send on", "local",
-		fmt.Sprintf("%v,[%v]:%d", integration.Local.IA, integration.Local.Host.L3, c.port))
+		fmt.Sprintf("%v,[%v]:%d", integration.Local.IA, integration.Local.Host.IP, c.port))
 	c.sdConn = integration.SDConn()
 	return integration.AttemptRepeatedly("End2End", c.attemptRequest)
 }
@@ -202,7 +202,7 @@ func (c client) ping(ctx context.Context, n int) error {
 	c.conn.SetWriteDeadline(getDeadline(ctx))
 	if remote.NextHop == nil {
 		remote.NextHop = &net.UDPAddr{
-			IP:   remote.Host.L3.IP(),
+			IP:   remote.Host.IP,
 			Port: topology.EndhostPort,
 		}
 	}
@@ -214,11 +214,11 @@ func (c client) ping(ctx context.Context, n int) error {
 			SCIONPacketInfo: snet.SCIONPacketInfo{
 				Destination: snet.SCIONAddress{
 					IA:   remote.IA,
-					Host: remote.Host.L3,
+					Host: addr.HostFromIP(remote.Host.IP),
 				},
 				Source: snet.SCIONAddress{
 					IA:   integration.Local.IA,
-					Host: integration.Local.Host.L3,
+					Host: addr.HostFromIP(integration.Local.Host.IP),
 				},
 				Path: remote.Path,
 				Extensions: []common.Extension{
@@ -228,7 +228,7 @@ func (c client) ping(ctx context.Context, n int) error {
 				},
 				L4Header: &l4.UDP{
 					SrcPort: c.port,
-					DstPort: remote.Host.L4,
+					DstPort: uint16(remote.Host.Port),
 				},
 				Payload: common.RawBytes(
 					pingMessage(remote.IA),
diff --git a/go/lib/infra/messenger/addr.go b/go/lib/infra/messenger/addr.go
index 989eac370..3847a3189 100644
--- a/go/lib/infra/messenger/addr.go
+++ b/go/lib/infra/messenger/addr.go
@@ -84,11 +84,7 @@ func (r AddressRewriter) RedirectToQUIC(ctx context.Context,
 	switch a := address.(type) {
 	case *snet.UDPAddr:
 		return a, false, nil
-	case *snet.Addr:
-		logger.Trace("Legacy snet.Addr is still being used", "addr", fmt.Sprintf("%v(%T)", a, a))
-		return r.RedirectToQUIC(ctx, a.ToXAddr())
 	case *snet.SVCAddr:
-
 		fa, err := r.buildFullAddress(ctx, a)
 		if err != nil {
 			return nil, false, err
diff --git a/go/lib/infra/messenger/messenger.go b/go/lib/infra/messenger/messenger.go
index 833a66f75..a9428e165 100644
--- a/go/lib/infra/messenger/messenger.go
+++ b/go/lib/infra/messenger/messenger.go
@@ -664,7 +664,6 @@ func (m *Messenger) SendChainIssueReply(ctx context.Context, msg *cert_mgmt.Chai
 func (m *Messenger) SendBeacon(ctx context.Context, msg *seg.Beacon, a net.Addr, id uint64) error {
 	logger := log.FromCtx(ctx)
 	switch a.(type) {
-	case *snet.Addr:
 	case *snet.UDPAddr:
 	case *snet.SVCAddr:
 		return common.NewBasicError("[Messenger] Cannot send to SVC address on QUIC-only RPC", nil,
@@ -787,8 +786,6 @@ func (m *Messenger) listenAndServeUDP() {
 			// functionality in the main ctrl libraries is still missing.
 			var ia addr.IA
 			switch v := address.(type) {
-			case *snet.Addr:
-				ia = v.IA
 			case *snet.UDPAddr:
 				ia = v.IA
 			default:
diff --git a/go/lib/infra/modules/trust/recurser.go b/go/lib/infra/modules/trust/recurser.go
index e07c4c16b..2a03a4e13 100644
--- a/go/lib/infra/modules/trust/recurser.go
+++ b/go/lib/infra/modules/trust/recurser.go
@@ -48,12 +48,6 @@ func (r ASLocalRecurser) AllowRecursion(peer net.Addr) error {
 	if peer == nil {
 		return nil
 	}
-
-	// TODO(roosd): Remove when snet.Addr is removed.
-	if a, ok := peer.(*snet.Addr); ok {
-		peer = a.ToXAddr()
-	}
-
 	a, ok := peer.(*snet.UDPAddr)
 	if !ok {
 		return serrors.WrapStr("unable to determine AS of peer", ErrRecursionNotAllowed,
diff --git a/go/lib/sciond/pathprobe/paths.go b/go/lib/sciond/pathprobe/paths.go
index 500b46ded..4ebba8d29 100644
--- a/go/lib/sciond/pathprobe/paths.go
+++ b/go/lib/sciond/pathprobe/paths.go
@@ -88,7 +88,7 @@ func FilterEmptyPaths(paths []snet.Path) []snet.Path {
 // Prober can be used to get the status of a path.
 type Prober struct {
 	DstIA    addr.IA
-	Local    snet.Addr
+	Local    snet.UDPAddr
 	DispPath string
 }
 
@@ -114,7 +114,7 @@ func (p Prober) GetStatuses(ctx context.Context,
 			SCMPHandler: scmpH,
 		},
 	)
-	snetConn, err := network.Listen(ctx, "udp", p.Local.ToNetUDPAddr(), addr.SvcNone)
+	snetConn, err := network.Listen(ctx, "udp", p.Local.Host, addr.SvcNone)
 	if err != nil {
 		return nil, common.NewBasicError("listening failed", err)
 	}
diff --git a/go/lib/snet/BUILD.bazel b/go/lib/snet/BUILD.bazel
index 59a89b29e..54acc19e6 100644
--- a/go/lib/snet/BUILD.bazel
+++ b/go/lib/snet/BUILD.bazel
@@ -51,6 +51,7 @@ go_test(
         "//go/lib/addr:go_default_library",
         "//go/lib/common:go_default_library",
         "//go/lib/layers:go_default_library",
+        "//go/lib/xtest:go_default_library",
         "@com_github_stretchr_testify//assert:go_default_library",
     ],
 )
diff --git a/go/lib/snet/addr.go b/go/lib/snet/addr.go
index 65887d23f..5673dd3a7 100644
--- a/go/lib/snet/addr.go
+++ b/go/lib/snet/addr.go
@@ -199,7 +199,7 @@ func parseAddr(s string) (map[string]string, error) {
 	return result, nil
 }
 
-// This method implements flag.Value interface
+// Set implements the flag.Value interface
 func (a *Addr) Set(s string) error {
 	other, err := AddrFromString(s)
 	if err != nil {
diff --git a/go/lib/snet/reader.go b/go/lib/snet/reader.go
index 784c36908..802704e4e 100644
--- a/go/lib/snet/reader.go
+++ b/go/lib/snet/reader.go
@@ -45,7 +45,7 @@ func newScionConnReader(base *scionConnBase, conn PacketConn) *scionConnReader {
 // address of the sender.
 func (c *scionConnReader) ReadFrom(b []byte) (int, net.Addr, error) {
 	n, a, err := c.read(b)
-	return n, a.ToAddr(), err
+	return n, a, err
 }
 
 // Read reads data into b from a connection with a fixed remote address. If the
diff --git a/go/lib/snet/svcaddr.go b/go/lib/snet/svcaddr.go
index fc8371bd1..3d93262db 100644
--- a/go/lib/snet/svcaddr.go
+++ b/go/lib/snet/svcaddr.go
@@ -31,17 +31,3 @@ func (a *SVCAddr) Network() string {
 func (a *SVCAddr) String() string {
 	return fmt.Sprintf("%v,%v", a.IA, a.SVC)
 }
-
-// ToAddr returns a legacy snet.Addr.
-func (a *SVCAddr) ToAddr() *Addr {
-	ret := &Addr{
-		IA:      a.IA,
-		NextHop: CopyUDPAddr(a.NextHop),
-		Host:    &addr.AppAddr{L3: a.SVC},
-	}
-	if a.Path != nil {
-		ret.Path = a.Path.Copy()
-	}
-	return ret
-
-}
diff --git a/go/lib/snet/udpaddr.go b/go/lib/snet/udpaddr.go
index b69f19f70..b94e5489a 100644
--- a/go/lib/snet/udpaddr.go
+++ b/go/lib/snet/udpaddr.go
@@ -29,25 +29,24 @@ func (a *UDPAddr) Network() string {
 
 // String implements net.Addr interface.
 func (a *UDPAddr) String() string {
-	return fmt.Sprintf("%v,[%v]:%v", a.IA, a.Host.IP, a.Host.Port)
+	var ip net.IP
+	var port int
+	if a.Host == nil {
+		ip = nil
+		port = 0
+	} else {
+		ip = a.Host.IP
+		port = a.Host.Port
+	}
+	return fmt.Sprintf("%v,[%v]:%v", a.IA, ip, port)
 }
 
-// ToAddr returns a legacy snet.Addr.
-func (a *UDPAddr) ToAddr() *Addr {
-	if a == nil {
-		return nil
-	}
-	ret := &Addr{
-		IA:      a.IA,
-		NextHop: CopyUDPAddr(a.NextHop),
-		Host: &addr.AppAddr{
-			L3: addr.HostFromIP(a.Host.IP),
-			L4: uint16(a.Host.Port),
-		},
+// Set implements the flag.Value interface
+func (a *UDPAddr) Set(s string) error {
+	other, err := AddrFromString(s)
+	if err != nil {
+		return err
 	}
-	if a.Path != nil {
-		ret.Path = a.Path.Copy()
-	}
-	return ret
-
+	*a = *other.ToXAddr().(*UDPAddr)
+	return nil
 }
diff --git a/go/sig/internal/disp/disp.go b/go/sig/internal/disp/disp.go
index 140a4a0a1..64fe35db6 100644
--- a/go/sig/internal/disp/disp.go
+++ b/go/sig/internal/disp/disp.go
@@ -53,7 +53,7 @@ func (rt RegType) String() string {
 type RegPld struct {
 	Id   mgmt.MsgIdType
 	P    interface{}
-	Addr *snet.Addr
+	Addr *snet.UDPAddr
 }
 
 type RegPldChan chan *RegPld
@@ -100,7 +100,7 @@ func (dm *dispRegistry) Unregister(regType RegType, key RegPollKey) error {
 	return nil
 }
 
-func (dm *dispRegistry) sigCtrl(pld *mgmt.Pld, addr *snet.Addr) {
+func (dm *dispRegistry) sigCtrl(pld *mgmt.Pld, addr *snet.UDPAddr) {
 	dm.Lock()
 	defer dm.Unlock()
 	u, err := pld.Union()
@@ -131,10 +131,15 @@ func (dm *dispRegistry) sigCtrl(pld *mgmt.Pld, addr *snet.Addr) {
 
 func dispFunc(dp *pktdisp.DispPkt) {
 	scpld, err := ctrl.NewSignedPldFromRaw(dp.Raw)
-	var src *snet.Addr
+	var src *snet.UDPAddr
 	switch v := dp.Addr.(type) {
-	case *snet.Addr:
-		src = v.Copy()
+	case *snet.UDPAddr:
+		src = snet.NewUDPAddr(
+			v.IA,
+			v.Path.Copy(),
+			snet.CopyUDPAddr(v.NextHop),
+			snet.CopyUDPAddr(v.Host),
+		)
 	default:
 		log.Error("Not valid snet address")
 		return
diff --git a/go/sig/internal/ingress/BUILD.bazel b/go/sig/internal/ingress/BUILD.bazel
index f3391fe4e..4548e74bd 100644
--- a/go/sig/internal/ingress/BUILD.bazel
+++ b/go/sig/internal/ingress/BUILD.bazel
@@ -33,6 +33,7 @@ go_test(
     deps = [
         "//go/lib/ringbuf:go_default_library",
         "//go/lib/snet:go_default_library",
+        "//go/lib/xtest:go_default_library",
         "@com_github_stretchr_testify//assert:go_default_library",
     ],
 )
diff --git a/go/sig/internal/ingress/dispatcher.go b/go/sig/internal/ingress/dispatcher.go
index bb1ec5092..3d1e84a81 100644
--- a/go/sig/internal/ingress/dispatcher.go
+++ b/go/sig/internal/ingress/dispatcher.go
@@ -84,7 +84,7 @@ func (d *Dispatcher) read() error {
 				frame.Release()
 			} else {
 				switch v := src.(type) {
-				case *snet.Addr:
+				case *snet.UDPAddr:
 					frame.frameLen = read
 					frame.sessId = mgmt.SessionType((frame.raw[0]))
 					d.updateMetrics(v.IA.IAInt(), frame.sessId, read)
@@ -105,7 +105,7 @@ func (d *Dispatcher) read() error {
 
 // dispatch dispatches a frame to the corresponding worker, spawning one if none
 // exist yet. Dispatching is done based on source ISD-AS -> source host Addr -> Sess Id.
-func (d *Dispatcher) dispatch(frame *FrameBuf, src *snet.Addr) {
+func (d *Dispatcher) dispatch(frame *FrameBuf, src *snet.UDPAddr) {
 	dispatchStr := fmt.Sprintf("%s/%s/%s", src.IA, src.Host, frame.sessId)
 	// Check if we already have a worker running and start one if not.
 	worker, ok := d.workers[dispatchStr]
diff --git a/go/sig/internal/ingress/worker.go b/go/sig/internal/ingress/worker.go
index 9c5a1c5c1..1cb5865ea 100644
--- a/go/sig/internal/ingress/worker.go
+++ b/go/sig/internal/ingress/worker.go
@@ -42,7 +42,7 @@ type sender interface {
 // Worker handles decapsulation of SIG frames.
 type Worker struct {
 	log.Logger
-	Remote           *snet.Addr
+	Remote           *snet.UDPAddr
 	SessId           mgmt.SessionType
 	Ring             *ringbuf.Ring
 	rlists           map[int]*ReassemblyList
@@ -51,7 +51,7 @@ type Worker struct {
 	tunIO            io.ReadWriteCloser
 }
 
-func NewWorker(remote *snet.Addr, sessId mgmt.SessionType, tunIO io.ReadWriteCloser) *Worker {
+func NewWorker(remote *snet.UDPAddr, sessId mgmt.SessionType, tunIO io.ReadWriteCloser) *Worker {
 	worker := &Worker{
 		Logger: log.New("ingress", remote.String(), "sessId", sessId),
 		Remote: remote,
diff --git a/go/tools/scmp/cmn/BUILD.bazel b/go/tools/scmp/cmn/BUILD.bazel
index 33b5f76ed..57e195c76 100644
--- a/go/tools/scmp/cmn/BUILD.bazel
+++ b/go/tools/scmp/cmn/BUILD.bazel
@@ -6,6 +6,7 @@ go_library(
     importpath = "github.com/scionproto/scion/go/tools/scmp/cmn",
     visibility = ["//visibility:public"],
     deps = [
+        "//go/lib/addr:go_default_library",
         "//go/lib/common:go_default_library",
         "//go/lib/ctrl/path_mgmt:go_default_library",
         "//go/lib/env:go_default_library",
diff --git a/go/tools/scmp/cmn/common.go b/go/tools/scmp/cmn/common.go
index df4c82740..10f1ace3b 100644
--- a/go/tools/scmp/cmn/common.go
+++ b/go/tools/scmp/cmn/common.go
@@ -25,6 +25,7 @@ import (
 	"syscall"
 	"time"
 
+	"github.com/scionproto/scion/go/lib/addr"
 	"github.com/scionproto/scion/go/lib/common"
 	"github.com/scionproto/scion/go/lib/ctrl/path_mgmt"
 	"github.com/scionproto/scion/go/lib/env"
@@ -56,9 +57,8 @@ var (
 	Interactive bool
 	Interval    time.Duration
 	Timeout     time.Duration
-	Local       snet.Addr
-	Remote      snet.Addr
-	Bind        snet.Addr
+	Local       snet.UDPAddr
+	Remote      snet.UDPAddr
 )
 
 var (
@@ -75,9 +75,8 @@ func init() {
 	flag.DurationVar(&Interval, "interval", DefaultInterval, "time between packets (echo only)")
 	flag.DurationVar(&Timeout, "timeout", DefaultTimeout, "timeout per packet")
 	flag.UintVar(&Count, "c", 0, "Total number of packet to send (echo only). Maximum value 65535")
-	flag.Var((*snet.Addr)(&Local), "local", "(Mandatory) address to listen on")
-	flag.Var((*snet.Addr)(&Remote), "remote", "(Mandatory for clients) address to connect to")
-	flag.Var((*snet.Addr)(&Bind), "bind", "address to bind to, if running behind NAT")
+	flag.Var(&Local, "local", "(Mandatory) address to listen on")
+	flag.Var(&Remote, "remote", "(Mandatory for clients) address to connect to")
 	flag.Usage = scmpUsage
 	Stats = &ScmpStats{}
 	Start = time.Now()
@@ -153,8 +152,8 @@ func NewSCMPPkt(t scmp.Type, info scmp.Info, ext common.Extension) *spkt.ScnPkt
 	pkt := &spkt.ScnPkt{
 		DstIA:   Remote.IA,
 		SrcIA:   Local.IA,
-		DstHost: Remote.Host.L3,
-		SrcHost: Local.Host.L3,
+		DstHost: addr.HostFromIP(Remote.Host.IP),
+		SrcHost: addr.HostFromIP(Local.Host.IP),
 		Path:    Remote.Path,
 		HBHExt:  exts,
 		L4:      scmpHdr,
@@ -167,7 +166,7 @@ func NextHopAddr() net.Addr {
 	var nhAddr *net.UDPAddr
 	if Remote.NextHop == nil {
 		nhAddr = &net.UDPAddr{
-			IP:   Remote.Host.L3.IP(),
+			IP:   Remote.Host.IP,
 			Port: topology.EndhostPort,
 		}
 	} else {
diff --git a/go/tools/scmp/main.go b/go/tools/scmp/main.go
index 519654c3b..19220fc77 100644
--- a/go/tools/scmp/main.go
+++ b/go/tools/scmp/main.go
@@ -69,7 +69,7 @@ func main() {
 	// Connect to the dispatcher
 	dispatcherService := reliable.NewDispatcher(*dispatcher)
 	cmn.Conn, _, err = dispatcherService.Register(context.Background(), cmn.Local.IA,
-		cmn.Local.ToNetUDPAddr(), addr.SvcNone)
+		cmn.Local.Host, addr.SvcNone)
 	if err != nil {
 		cmn.Fatal("Unable to register with the dispatcher addr=%s\nerr=%v", cmn.Local, err)
 	}
diff --git a/go/tools/scmp/traceroute/BUILD.bazel b/go/tools/scmp/traceroute/BUILD.bazel
index 15f6c027a..3aeade0f2 100644
--- a/go/tools/scmp/traceroute/BUILD.bazel
+++ b/go/tools/scmp/traceroute/BUILD.bazel
@@ -6,6 +6,7 @@ go_library(
     importpath = "github.com/scionproto/scion/go/tools/scmp/traceroute",
     visibility = ["//visibility:public"],
     deps = [
+        "//go/lib/addr:go_default_library",
         "//go/lib/common:go_default_library",
         "//go/lib/hpkt:go_default_library",
         "//go/lib/layers:go_default_library",
diff --git a/go/tools/scmp/traceroute/traceroute.go b/go/tools/scmp/traceroute/traceroute.go
index 76b86c87d..ce77c4b26 100644
--- a/go/tools/scmp/traceroute/traceroute.go
+++ b/go/tools/scmp/traceroute/traceroute.go
@@ -20,6 +20,7 @@ import (
 	"os"
 	"time"
 
+	"github.com/scionproto/scion/go/lib/addr"
 	"github.com/scionproto/scion/go/lib/common"
 	"github.com/scionproto/scion/go/lib/hpkt"
 	"github.com/scionproto/scion/go/lib/layers"
@@ -148,7 +149,9 @@ func prettyPrint(pkt *spkt.ScnPkt, info *scmp.InfoTraceRoute, rtt time.Duration)
 
 // hopPktOff returns HopF offset relative to the packet
 func hopPktOff(offset int) uint8 {
-	off := spkt.CmnHdrLen + spkt.AddrHdrLen(cmn.Local.Host.L3, cmn.Remote.Host.L3) + offset
+	off := spkt.CmnHdrLen +
+		spkt.AddrHdrLen(addr.HostFromIP(cmn.Local.Host.IP), addr.HostFromIP(cmn.Remote.Host.IP)) +
+		offset
 	return uint8(off / common.LineLen)
 }
 
diff --git a/go/tools/showpaths/paths.go b/go/tools/showpaths/paths.go
index e938d5bbb..92b9dfec8 100644
--- a/go/tools/showpaths/paths.go
+++ b/go/tools/showpaths/paths.go
@@ -47,11 +47,11 @@ var (
 var (
 	dstIA addr.IA
 	srcIA addr.IA
-	local snet.Addr
+	local snet.UDPAddr
 )
 
 func init() {
-	flag.Var((*snet.Addr)(&local), "local", "Local address to use for health checks")
+	flag.Var(&local, "local", "Local address to use for health checks")
 	flag.Usage = flagUsage
 }
 


Test patch:
diff --git a/go/cs/beaconing/handler_test.go b/go/cs/beaconing/handler_test.go
index 6544a805b..ce403e51f 100644
--- a/go/cs/beaconing/handler_test.go
+++ b/go/cs/beaconing/handler_test.go
@@ -27,6 +27,7 @@ import (
 	"github.com/scionproto/scion/go/cs/beaconing/mock_beaconing"
 	"github.com/scionproto/scion/go/cs/ifstate"
 	"github.com/scionproto/scion/go/cs/metrics"
+	"github.com/scionproto/scion/go/lib/addr"
 	"github.com/scionproto/scion/go/lib/common"
 	"github.com/scionproto/scion/go/lib/ctrl"
 	"github.com/scionproto/scion/go/lib/ctrl/seg"
@@ -89,7 +90,7 @@ func TestNewHandler(t *testing.T) {
 	handler := NewHandler(localIA, intfs, inserter, verifier)
 	t.Run("Wrong payload type", func(t *testing.T) {
 		req := infra.NewRequest(context.Background(), &ctrl.Pld{}, nil,
-			&snet.Addr{Path: testPath(localIF)}, 0)
+			snet.NewUDPAddr(addr.IA{}, testPath(localIF), nil, nil), 0)
 		res := handler.Handle(req)
 		assert.Equal(t, res, infra.MetricsErrInternal)
 	})
@@ -113,14 +114,14 @@ func TestNewHandler(t *testing.T) {
 	t.Run("Invalid hop field", func(t *testing.T) {
 		req := infra.NewRequest(
 			infra.NewContextWithResponseWriter(context.Background(), rw),
-			pseg, nil, &snet.Addr{Path: &spath.Path{}}, 0)
+			pseg, nil, snet.NewUDPAddr(addr.IA{}, &spath.Path{}, nil, nil), 0)
 		res := handler.Handle(req)
 		assert.Equal(t, res, infra.MetricsErrInvalid)
 	})
 	t.Run("Invalid unknown interface", func(t *testing.T) {
 		req := infra.NewRequest(
 			infra.NewContextWithResponseWriter(context.Background(), rw),
-			pseg, nil, &snet.Addr{Path: testPath(12)}, 0)
+			pseg, nil, snet.NewUDPAddr(addr.IA{}, testPath(12), nil, nil), 0)
 		res := handler.Handle(req)
 		assert.Equal(t, res, infra.MetricsErrInvalid)
 	})
@@ -129,7 +130,7 @@ func TestNewHandler(t *testing.T) {
 	t.Run("Invalid link type", func(t *testing.T) {
 		req := infra.NewRequest(
 			infra.NewContextWithResponseWriter(context.Background(), rw),
-			pseg, nil, &snet.Addr{Path: testPath(42)}, 0)
+			pseg, nil, snet.NewUDPAddr(addr.IA{}, testPath(42), nil, nil), 0)
 		res := handler.Handle(req)
 		assert.Equal(t, res, infra.MetricsErrInvalid)
 	})
@@ -201,7 +202,7 @@ func defaultTestReq(rw infra.ResponseWriter, pseg *seg.PathSegment) *infra.Reque
 		infra.NewContextWithResponseWriter(context.Background(), rw),
 		pseg,
 		nil,
-		&snet.Addr{Path: testPath(localIF)},
+		snet.NewUDPAddr(addr.IA{}, testPath(localIF), nil, nil),
 		0,
 	)
 }
diff --git a/go/cs/keepalive/handler_test.go b/go/cs/keepalive/handler_test.go
index 45e4b0150..d98ac439d 100644
--- a/go/cs/keepalive/handler_test.go
+++ b/go/cs/keepalive/handler_test.go
@@ -79,7 +79,7 @@ func TestNewHandler(t *testing.T) {
 			RevDropper:    dropper,
 		})
 		req := infra.NewRequest(context.Background(), &ifid.IFID{OrigIfID: originIF}, nil,
-			&snet.Addr{IA: originIA, Path: testPath(localIF)}, 0)
+			snet.NewUDPAddr(originIA, testPath(localIF), nil, nil), 0)
 		res := handler.Handle(req)
 		waitTimeout(t, wg)
 		assert.Equal(t, res, infra.MetricsResultOk)
@@ -91,7 +91,7 @@ func TestNewHandler(t *testing.T) {
 		intfs.Get(localIF).Activate(42)
 		handler := NewHandler(localIA, intfs, zeroCallTasks(mctrl))
 		req := infra.NewRequest(context.Background(), &ifid.IFID{OrigIfID: originIF}, nil,
-			&snet.Addr{IA: originIA, Path: testPath(localIF)}, 0)
+			snet.NewUDPAddr(originIA, testPath(localIF), nil, nil), 0)
 		res := handler.Handle(req)
 		assert.Equal(t, res, infra.MetricsResultOk)
 	})
@@ -107,7 +107,7 @@ func TestNewHandler(t *testing.T) {
 			{
 				msg: "Wrong payload type",
 				req: infra.NewRequest(context.Background(), &ctrl.Pld{}, nil,
-					&snet.Addr{IA: originIA, Path: testPath(localIF)}, 0),
+					snet.NewUDPAddr(originIA, testPath(localIF), nil, nil), 0),
 				exp: infra.MetricsErrInternal,
 			},
 			{
@@ -119,19 +119,19 @@ func TestNewHandler(t *testing.T) {
 			{
 				msg: "Invalid path",
 				req: infra.NewRequest(context.Background(), &ifid.IFID{OrigIfID: originIF}, nil,
-					&snet.Addr{IA: originIA, Path: &spath.Path{}}, 0),
+					snet.NewUDPAddr(originIA, &spath.Path{}, nil, nil), 0),
 				exp: infra.MetricsErrInvalid,
 			},
 			{
 				msg: "Invalid ConsIngress ifid",
 				req: infra.NewRequest(context.Background(), &ifid.IFID{OrigIfID: originIF}, nil,
-					&snet.Addr{IA: originIA, Path: testPath(originIF)}, 0),
+					snet.NewUDPAddr(originIA, testPath(originIF), nil, nil), 0),
 				exp: infra.MetricsErrInvalid,
 			},
 			{
 				msg: "Invalid IA",
 				req: infra.NewRequest(context.Background(), &ifid.IFID{OrigIfID: originIF}, nil,
-					&snet.Addr{IA: localIA, Path: testPath(localIF)}, 0),
+					snet.NewUDPAddr(localIA, testPath(localIF), nil, nil), 0),
 				exp: infra.MetricsErrInvalid,
 			},
 		}
diff --git a/go/hidden_path_srv/internal/hpcfgreq/handler_test.go b/go/hidden_path_srv/internal/hpcfgreq/handler_test.go
index b4dd58e6f..b49db3514 100644
--- a/go/hidden_path_srv/internal/hpcfgreq/handler_test.go
+++ b/go/hidden_path_srv/internal/hpcfgreq/handler_test.go
@@ -92,9 +92,7 @@ func TestCfgReq(t *testing.T) {
 			msg := &path_mgmt.HPCfgReq{
 				ChangedSince: 0,
 			}
-			peer := &snet.Addr{
-				IA: ia110,
-			}
+			peer := snet.NewUDPAddr(ia110, nil, nil, nil)
 			req := infra.NewRequest(ctx, msg, nil, peer, 0)
 			reply := &path_mgmt.HPCfgReply{
 				Cfgs: []*path_mgmt.HPCfg{group1.ToMsg(), group2.ToMsg(), group3.ToMsg()},
@@ -139,10 +137,7 @@ func TestCfgReq(t *testing.T) {
 			msg := &path_mgmt.HPCfgReq{
 				ChangedSince: 0,
 			}
-			peer := &snet.Addr{
-				IA:   ia111,
-				Host: addr.NewSVCUDPAppAddr(addr.SvcHPS),
-			}
+			peer := snet.NewUDPAddr(ia111, nil, nil, nil)
 			req := infra.NewRequest(ctx, msg, nil, peer, 0)
 			ack := ack.Ack{
 				Err:     proto.Ack_ErrCode_reject,
diff --git a/go/hidden_path_srv/internal/hpsegreq/fetcher_test.go b/go/hidden_path_srv/internal/hpsegreq/fetcher_test.go
index 17e3fed22..36085826b 100644
--- a/go/hidden_path_srv/internal/hpsegreq/fetcher_test.go
+++ b/go/hidden_path_srv/internal/hpsegreq/fetcher_test.go
@@ -128,7 +128,7 @@ func TestFetcher(t *testing.T) {
 	newTestGraph(t, gomock.NewController(t))
 	tests := map[string]struct {
 		req   *path_mgmt.HPSegReq
-		peer  *snet.Addr
+		peer  *snet.UDPAddr
 		err   error
 		res   []*path_mgmt.HPSegRecs
 		setup func(mockDB *mock_pathdb.MockPathDB, mockMsgr *mock_infra.MockMessenger)
@@ -138,7 +138,7 @@ func TestFetcher(t *testing.T) {
 				RawDstIA: ia111.IAInt(),
 				GroupIds: []*path_mgmt.HPGroupId{group1.Id.ToMsg()},
 			},
-			peer: &snet.Addr{IA: ia113},
+			peer: snet.NewUDPAddr(ia113, nil, nil, nil),
 			res: []*path_mgmt.HPSegRecs{
 				{
 					GroupId: group1.Id.ToMsg(),
@@ -159,7 +159,7 @@ func TestFetcher(t *testing.T) {
 				RawDstIA: ia111.IAInt(),
 				GroupIds: []*path_mgmt.HPGroupId{group2.Id.ToMsg()},
 			},
-			peer: &snet.Addr{IA: ia113},
+			peer: snet.NewUDPAddr(ia113, nil, nil, nil),
 			res: []*path_mgmt.HPSegRecs{
 				{
 					GroupId: group2.Id.ToMsg(),
@@ -179,7 +179,7 @@ func TestFetcher(t *testing.T) {
 						},
 					},
 				}
-				addr := &snet.Addr{IA: ia115, Host: addr.NewSVCUDPAppAddr(addr.SvcHPS)}
+				addr := snet.NewSVCAddr(ia115, nil, nil, addr.SvcHPS)
 				mockMsgr.EXPECT().GetHPSegs(gomock.Any(), gomock.Any(),
 					addr, gomock.Any()).Return(reply, nil)
 			},
@@ -189,7 +189,7 @@ func TestFetcher(t *testing.T) {
 				RawDstIA: ia111.IAInt(),
 				GroupIds: []*path_mgmt.HPGroupId{group1.Id.ToMsg(), group2.Id.ToMsg()},
 			},
-			peer: &snet.Addr{IA: ia113},
+			peer: snet.NewUDPAddr(ia113, nil, nil, nil),
 			res: []*path_mgmt.HPSegRecs{
 				{
 					GroupId: group1.Id.ToMsg(),
@@ -218,7 +218,7 @@ func TestFetcher(t *testing.T) {
 						},
 					},
 				}
-				addr := &snet.Addr{IA: ia115, Host: addr.NewSVCUDPAppAddr(addr.SvcHPS)}
+				addr := snet.NewSVCAddr(ia115, nil, nil, addr.SvcHPS)
 				mockDB.EXPECT().Get(gomock.Any(), gomock.Any()).Return(res, nil)
 				mockMsgr.EXPECT().GetHPSegs(gomock.Any(), gomock.Any(), addr,
 					gomock.Any()).Return(reply, nil)
@@ -229,7 +229,7 @@ func TestFetcher(t *testing.T) {
 				RawDstIA: ia111.IAInt(),
 				GroupIds: []*path_mgmt.HPGroupId{group2.Id.ToMsg(), group3.Id.ToMsg()},
 			},
-			peer: &snet.Addr{IA: ia113},
+			peer: snet.NewUDPAddr(ia113, nil, nil, nil),
 			res: []*path_mgmt.HPSegRecs{
 				{
 					GroupId: group2.Id.ToMsg(),
@@ -265,10 +265,10 @@ func TestFetcher(t *testing.T) {
 						},
 					},
 				}
-				addr2 := &snet.Addr{IA: ia115, Host: addr.NewSVCUDPAppAddr(addr.SvcHPS)}
+				addr2 := snet.NewSVCAddr(ia115, nil, nil, addr.SvcHPS)
 				mockMsgr.EXPECT().GetHPSegs(gomock.Any(), gomock.Any(), addr2,
 					gomock.Any()).Return(reply2, nil)
-				addr3 := &snet.Addr{IA: ia114, Host: addr.NewSVCUDPAppAddr(addr.SvcHPS)}
+				addr3 := snet.NewSVCAddr(ia114, nil, nil, addr.SvcHPS)
 				mockMsgr.EXPECT().GetHPSegs(gomock.Any(), gomock.Any(), addr3,
 					gomock.Any()).Return(reply3, nil)
 			},
@@ -278,7 +278,7 @@ func TestFetcher(t *testing.T) {
 				RawDstIA: ia111.IAInt(),
 				GroupIds: []*path_mgmt.HPGroupId{group1.Id.ToMsg()},
 			},
-			peer: &snet.Addr{IA: ia113},
+			peer: snet.NewUDPAddr(ia113, nil, nil, nil),
 			res: []*path_mgmt.HPSegRecs{
 				{
 					GroupId: group1.Id.ToMsg(),
@@ -294,7 +294,7 @@ func TestFetcher(t *testing.T) {
 				RawDstIA: ia111.IAInt(),
 				GroupIds: []*path_mgmt.HPGroupId{group2.Id.ToMsg()},
 			},
-			peer: &snet.Addr{IA: ia113},
+			peer: snet.NewUDPAddr(ia113, nil, nil, nil),
 			res: []*path_mgmt.HPSegRecs{
 				{
 					GroupId: group2.Id.ToMsg(),
@@ -302,7 +302,7 @@ func TestFetcher(t *testing.T) {
 				},
 			},
 			setup: func(mockDB *mock_pathdb.MockPathDB, mockMsgr *mock_infra.MockMessenger) {
-				addr := &snet.Addr{IA: ia115, Host: addr.NewSVCUDPAppAddr(addr.SvcHPS)}
+				addr := snet.NewSVCAddr(ia115, nil, nil, addr.SvcHPS)
 				mockMsgr.EXPECT().GetHPSegs(gomock.Any(), gomock.Any(),
 					addr, gomock.Any()).Return(nil, errors.New("dummy"))
 			},
@@ -312,7 +312,7 @@ func TestFetcher(t *testing.T) {
 				RawDstIA: ia111.IAInt(),
 				GroupIds: []*path_mgmt.HPGroupId{wrongId.ToMsg()},
 			},
-			peer:  &snet.Addr{IA: ia114},
+			peer:  snet.NewUDPAddr(ia114, nil, nil, nil),
 			err:   hpsegreq.ErrUnknownGroup,
 			setup: func(mockDB *mock_pathdb.MockPathDB, mockMsgr *mock_infra.MockMessenger) {},
 		},
@@ -321,7 +321,7 @@ func TestFetcher(t *testing.T) {
 				RawDstIA: ia111.IAInt(),
 				GroupIds: []*path_mgmt.HPGroupId{group1.Id.ToMsg()},
 			},
-			peer:  &snet.Addr{IA: ia114},
+			peer:  snet.NewUDPAddr(ia114, nil, nil, nil),
 			err:   hpsegreq.ErrNotReader,
 			setup: func(mockDB *mock_pathdb.MockPathDB, mockMsgr *mock_infra.MockMessenger) {},
 		},
diff --git a/go/hidden_path_srv/internal/hpsegreq/handler_test.go b/go/hidden_path_srv/internal/hpsegreq/handler_test.go
index 35fee03fc..dbc80e18f 100644
--- a/go/hidden_path_srv/internal/hpsegreq/handler_test.go
+++ b/go/hidden_path_srv/internal/hpsegreq/handler_test.go
@@ -48,9 +48,7 @@ func TestSegReq(t *testing.T) {
 				RawDstIA: ia111.IAInt(),
 				GroupIds: []*path_mgmt.HPGroupId{group1.Id.ToMsg()},
 			}
-			peer := &snet.Addr{
-				Host: addr.NewSVCUDPAppAddr(addr.SvcHPS),
-			}
+			peer := snet.NewUDPAddr(addr.IA{}, nil, nil, nil)
 			req := infra.NewRequest(ctx, msg, nil, peer, 0)
 			recs := []*path_mgmt.HPSegRecs{
 				{
@@ -101,9 +99,7 @@ func TestSegReq(t *testing.T) {
 				RawDstIA: ia111.IAInt(),
 				GroupIds: []*path_mgmt.HPGroupId{group1.Id.ToMsg()},
 			}
-			peer := &snet.Addr{
-				Host: addr.NewSVCUDPAppAddr(addr.SvcHPS),
-			}
+			peer := snet.NewUDPAddr(addr.IA{}, nil, nil, nil)
 			req := infra.NewRequest(ctx, msg, nil, peer, 0)
 			m.fetcher.EXPECT().Fetch(gomock.Any(), gomock.Any(),
 				gomock.Any()).Return(nil, errors.New("dummy"))
diff --git a/go/hidden_path_srv/internal/registration/handler_test.go b/go/hidden_path_srv/internal/registration/handler_test.go
index ec6313e6d..5dac1f2e4 100644
--- a/go/hidden_path_srv/internal/registration/handler_test.go
+++ b/go/hidden_path_srv/internal/registration/handler_test.go
@@ -53,9 +53,7 @@ func TestSegReg(t *testing.T) {
 					Recs:    []*seg.Meta{seg110_133},
 				},
 			}
-			peer := &snet.Addr{
-				Host: addr.NewSVCUDPAppAddr(addr.SvcBS),
-			}
+			peer := snet.NewUDPAddr(addr.IA{}, nil, nil, nil)
 			req := infra.NewRequest(ctx, msg, nil, peer, 0)
 			ack := ack.Ack{
 				Err:     proto.Ack_ErrCode_ok,
@@ -124,26 +122,6 @@ func TestSegReg(t *testing.T) {
 			res := handler.Handle(req)
 			assert.Equal(t, infra.MetricsErrInvalid, res)
 		},
-		"invalid peer hop field": func(t *testing.T, ctx context.Context,
-			handler infra.Handler, m *mocks) {
-
-			msg := &path_mgmt.HPSegReg{
-				HPSegRecs: &path_mgmt.HPSegRecs{
-					Recs: []*seg.Meta{seg110_133},
-				},
-			}
-			peer := &snet.Addr{
-				Path: &spath.Path{},
-			}
-			req := infra.NewRequest(ctx, msg, nil, peer, 0)
-			ack := ack.Ack{
-				Err:     proto.Ack_ErrCode_reject,
-				ErrDesc: messenger.AckRejectFailedToParse,
-			}
-			m.rw.EXPECT().SendAckReply(gomock.Any(), &matchers.AckMsg{Ack: ack})
-			res := handler.Handle(req)
-			assert.Equal(t, infra.MetricsErrInvalid, res)
-		},
 		"group validation fails": func(t *testing.T, ctx context.Context,
 			handler infra.Handler, m *mocks) {
 
@@ -153,9 +131,7 @@ func TestSegReg(t *testing.T) {
 					Recs:    []*seg.Meta{seg110_133},
 				},
 			}
-			peer := &snet.Addr{
-				Host: addr.NewSVCUDPAppAddr(addr.SvcBS),
-			}
+			peer := snet.NewUDPAddr(addr.IA{}, &spath.Path{}, nil, nil)
 			req := infra.NewRequest(ctx, msg, nil, peer, 0)
 			ack := ack.Ack{
 				Err:     proto.Ack_ErrCode_reject,
diff --git a/go/lib/snet/udpaddr_test.go b/go/lib/snet/udpaddr_test.go
index 4552913a4..0c3264bf5 100644
--- a/go/lib/snet/udpaddr_test.go
+++ b/go/lib/snet/udpaddr_test.go
@@ -7,6 +7,7 @@ import (
 	"github.com/stretchr/testify/assert"
 
 	"github.com/scionproto/scion/go/lib/snet"
+	"github.com/scionproto/scion/go/lib/xtest"
 )
 
 func TestUDPAddrInterface(t *testing.T) {
@@ -21,6 +22,10 @@ func TestUDPAddrString(t *testing.T) {
 		want  string
 	}{
 		"empty": {
+			input: &snet.UDPAddr{},
+			want:  "0-0,[<nil>]:0",
+		},
+		"empty host": {
 			input: &snet.UDPAddr{Host: &net.UDPAddr{}},
 			want:  "0-0,[<nil>]:0",
 		},
@@ -32,3 +37,55 @@ func TestUDPAddrString(t *testing.T) {
 		})
 	}
 }
+
+func TestUDPAddrSet(t *testing.T) {
+	testCases := map[string]struct {
+		Input string
+		Error assert.ErrorAssertionFunc
+		Want  *snet.UDPAddr
+	}{
+		"empty string": {
+			Input: "",
+			Error: assert.Error,
+		},
+		"malformed IA": {
+			Input: "1-ff000:0:0,[192.168.1.1]:80",
+			Error: assert.Error,
+		},
+		"malformed IP": {
+			Input: "1-ff00:0:1,[192.1688.1.1]:80",
+			Error: assert.Error,
+		},
+		"malformed port": {
+			Input: "1-ff00:0:1,[192.168.1.1]:123456",
+			Error: assert.Error,
+		},
+		"bad symbol": {
+			Input: "1-ff00:0:1x[192.168.1.1]:80",
+			Error: assert.Error,
+		},
+		"good input": {
+			Input: "1-ff00:0:1,[192.168.1.1]:80",
+			Error: assert.NoError,
+			Want: snet.NewUDPAddr(
+				xtest.MustParseIA("1-ff00:0:1"),
+				nil,
+				nil,
+				&net.UDPAddr{
+					IP:   net.IP{192, 168, 1, 1},
+					Port: 80,
+				},
+			),
+		},
+	}
+	for n, tc := range testCases {
+		t.Run(n, func(t *testing.T) {
+			var a snet.UDPAddr
+			err := a.Set(tc.Input)
+			tc.Error(t, err)
+			if err == nil {
+				assert.Equal(t, tc.Want, &a)
+			}
+		})
+	}
+}
diff --git a/go/lib/sock/reliable/reconnect/conn_io_test.go b/go/lib/sock/reliable/reconnect/conn_io_test.go
index 670cf2633..650bdf68e 100644
--- a/go/lib/sock/reliable/reconnect/conn_io_test.go
+++ b/go/lib/sock/reliable/reconnect/conn_io_test.go
@@ -188,7 +188,7 @@ func TestPacketConnReadWrite(t *testing.T) {
 		Convey("Reads on packet conn must call the same function on the underlying conn", func() {
 			buffer := make([]byte, 3)
 			readData := []byte{4, 5}
-			mockReadFunc := func(b []byte) (int, *snet.Addr, error) {
+			mockReadFunc := func(b []byte) (int, *snet.UDPAddr, error) {
 				copy(b, readData)
 				return len(readData), remoteAddr, nil
 			}
diff --git a/go/lib/sock/reliable/reconnect/main_test.go b/go/lib/sock/reliable/reconnect/main_test.go
index 6382fb9dc..2c6ddb20d 100644
--- a/go/lib/sock/reliable/reconnect/main_test.go
+++ b/go/lib/sock/reliable/reconnect/main_test.go
@@ -55,12 +55,12 @@ var (
 	connectErrorFromDispatcher = serrors.New("Port unavailable")
 )
 
-func MustParseSnet(str string) *snet.Addr {
-	address, err := snet.AddrFromString(str)
-	if err != nil {
+func MustParseSnet(str string) *snet.UDPAddr {
+	var a snet.UDPAddr
+	if err := a.Set(str); err != nil {
 		panic(fmt.Sprintf("bad snet string %v, err=%v", str, err))
 	}
-	return address
+	return &a
 }
 
 // tickerMultiplier computes durations relative to the default reconnect
diff --git a/go/lib/sock/reliable/reconnect/network_test.go b/go/lib/sock/reliable/reconnect/network_test.go
index ca269ae8e..60c6aefa6 100644
--- a/go/lib/sock/reliable/reconnect/network_test.go
+++ b/go/lib/sock/reliable/reconnect/network_test.go
@@ -33,20 +33,19 @@ import (
 )
 
 func TestReconnect(t *testing.T) {
-	Convey("Reconnections must conserve local and bind addresses", t, func() {
+	Convey("Reconnections must conserve local address", t, func() {
 		ctrl := gomock.NewController(t)
 		defer ctrl.Finish()
 		mockDispatcher := mock_reliable.NewMockDispatcher(ctrl)
-		Convey("Given a mocked underlying connection with local and bind", func() {
+		Convey("Given a mocked underlying connection with local", func() {
 			mockConn := mock_net.NewMockPacketConn(ctrl)
 			Convey("Allocated ports are reused on subsequent attempts", func() {
 				mockDispatcher.EXPECT().
-					Register(context.Background(), localAddr.IA,
-						localNoPortAddr.ToNetUDPAddr(), svc).
+					Register(context.Background(), localAddr.IA, localNoPortAddr.Host, svc).
 					Return(mockConn, uint16(80), nil)
 
 				want := &net.UDPAddr{
-					IP:   localNoPortAddr.Host.Copy().L3.IP(),
+					IP:   append(localNoPortAddr.Host.IP[:0:0], localNoPortAddr.Host.IP...),
 					Port: 80,
 				}
 
@@ -56,7 +55,7 @@ func TestReconnect(t *testing.T) {
 
 				network := reconnect.NewDispatcherService(mockDispatcher)
 				packetConn, _, _ := network.Register(context.Background(), localAddr.IA,
-					localNoPortAddr.ToNetUDPAddr(), svc)
+					localNoPortAddr.Host, svc)
 				packetConn.(*reconnect.PacketConn).Reconnect()
 			})
 		})
diff --git a/go/sig/internal/ingress/worker_test.go b/go/sig/internal/ingress/worker_test.go
index 8fdb7958f..076626570 100644
--- a/go/sig/internal/ingress/worker_test.go
+++ b/go/sig/internal/ingress/worker_test.go
@@ -15,12 +15,14 @@
 package ingress
 
 import (
+	"net"
 	"testing"
 
 	"github.com/stretchr/testify/assert"
 
 	"github.com/scionproto/scion/go/lib/ringbuf"
 	"github.com/scionproto/scion/go/lib/snet"
+	"github.com/scionproto/scion/go/lib/xtest"
 )
 
 type MockTun struct {
@@ -61,8 +63,15 @@ func SendFrame(t *testing.T, w *Worker, data []byte) {
 }
 
 func TestParsing(t *testing.T) {
-	addr, err := snet.AddrFromString("1-ff00:0:300,[192.168.1.1]:80")
-	assert.NoError(t, err)
+	addr := snet.NewUDPAddr(
+		xtest.MustParseIA("1-ff00:0:300"),
+		nil,
+		nil,
+		&net.UDPAddr{
+			IP:   net.IP{192, 168, 1, 1},
+			Port: 80,
+		},
+	)
 	mt := &MockTun{}
 	w := NewWorker(addr, 1, mt)