diff options
author | Chris Kuiper <ckuiper@google.com> | 2018-12-06 11:47:17 -0800 |
---|---|---|
committer | Shentubot <shentubot@google.com> | 2018-12-06 11:48:12 -0800 |
commit | 1b3442cae017c4870baf2ed878c63f171029a662 (patch) | |
tree | 6d0d288d363042b3d9a56d9c7678c26fd9864d2b /pkg | |
parent | 666db00c262c7d6d6359fbaba28e344d015a7823 (diff) |
Allow sending of broadcast packets w/o route.
Currently sending a broadcast packet (for DHCP, e.g.) requires a "default
route" of the format "0.0.0.0/0 via 0.0.0.0 <intf>". There is no good reason
for this and on devices with several ports this creates a rather akward route
table with lots of such default routes (which defeats the purpose of a default
route).
PiperOrigin-RevId: 224378769
Change-Id: Icd7ec8a206eb08083cff9a837f6f9ab231c73a19
Diffstat (limited to 'pkg')
-rw-r--r-- | pkg/tcpip/stack/BUILD | 1 | ||||
-rw-r--r-- | pkg/tcpip/stack/stack.go | 24 | ||||
-rw-r--r-- | pkg/tcpip/stack/stack_test.go | 39 |
3 files changed, 57 insertions, 7 deletions
diff --git a/pkg/tcpip/stack/BUILD b/pkg/tcpip/stack/BUILD index 5e7355135..90cc05cda 100644 --- a/pkg/tcpip/stack/BUILD +++ b/pkg/tcpip/stack/BUILD @@ -40,6 +40,7 @@ go_test( ":stack", "//pkg/tcpip", "//pkg/tcpip/buffer", + "//pkg/tcpip/header", "//pkg/tcpip/link/channel", "//pkg/waiter", ], diff --git a/pkg/tcpip/stack/stack.go b/pkg/tcpip/stack/stack.go index 7af343fba..d39878a88 100644 --- a/pkg/tcpip/stack/stack.go +++ b/pkg/tcpip/stack/stack.go @@ -716,12 +716,29 @@ func (s *Stack) GetMainNICAddress(id tcpip.NICID, protocol tcpip.NetworkProtocol return "", tcpip.Subnet{}, tcpip.ErrUnknownNICID } +func (s *Stack) getRefEP(nic *NIC, localAddr tcpip.Address, netProto tcpip.NetworkProtocolNumber) (ref *referencedNetworkEndpoint) { + if len(localAddr) == 0 { + return nic.primaryEndpoint(netProto) + } + return nic.findEndpoint(netProto, localAddr, CanBePrimaryEndpoint) +} + // FindRoute creates a route to the given destination address, leaving through // the given nic and local address (if provided). func (s *Stack) FindRoute(id tcpip.NICID, localAddr, remoteAddr tcpip.Address, netProto tcpip.NetworkProtocolNumber) (Route, *tcpip.Error) { s.mu.RLock() defer s.mu.RUnlock() + // We don't require a route in the table to send a broadcast out on a NIC. + if id != 0 && remoteAddr == header.IPv4Broadcast { + if nic, ok := s.nics[id]; ok { + if ref := s.getRefEP(nic, localAddr, netProto); ref != nil { + return makeRoute(netProto, ref.ep.ID().LocalAddress, remoteAddr, nic.linkEP.LinkAddress(), ref), nil + } + } + return Route{}, tcpip.ErrNoRoute + } + for i := range s.routeTable { if (id != 0 && id != s.routeTable[i].NIC) || (len(remoteAddr) != 0 && !s.routeTable[i].Match(remoteAddr)) { continue @@ -732,12 +749,7 @@ func (s *Stack) FindRoute(id tcpip.NICID, localAddr, remoteAddr tcpip.Address, n continue } - var ref *referencedNetworkEndpoint - if len(localAddr) != 0 { - ref = nic.findEndpoint(netProto, localAddr, CanBePrimaryEndpoint) - } else { - ref = nic.primaryEndpoint(netProto) - } + ref := s.getRefEP(nic, localAddr, netProto) if ref == nil { continue } diff --git a/pkg/tcpip/stack/stack_test.go b/pkg/tcpip/stack/stack_test.go index 8a9c9d234..dc05517ba 100644 --- a/pkg/tcpip/stack/stack_test.go +++ b/pkg/tcpip/stack/stack_test.go @@ -26,6 +26,7 @@ import ( "gvisor.googlesource.com/gvisor/pkg/tcpip" "gvisor.googlesource.com/gvisor/pkg/tcpip/buffer" + "gvisor.googlesource.com/gvisor/pkg/tcpip/header" "gvisor.googlesource.com/gvisor/pkg/tcpip/link/channel" "gvisor.googlesource.com/gvisor/pkg/tcpip/stack" ) @@ -643,6 +644,42 @@ func TestAddressSpoofing(t *testing.T) { } } +func TestBroadcastNeedsNoRoute(t *testing.T) { + s := stack.New([]string{"fakeNet"}, nil, stack.Options{}) + + id, _ := channel.New(10, defaultMTU, "") + if err := s.CreateNIC(1, id); err != nil { + t.Fatalf("CreateNIC failed: %v", err) + } + s.SetRouteTable([]tcpip.Route{}) + + // If there is no endpoint, it won't work. + if _, err := s.FindRoute(1, header.IPv4Any, header.IPv4Broadcast, fakeNetNumber); err != tcpip.ErrNoRoute { + t.Fatalf("got FindRoute(1, %v, %v, %v) = %v, want = %v", header.IPv4Any, header.IPv4Broadcast, fakeNetNumber, err, tcpip.ErrNoRoute) + } + + if err := s.AddAddress(1, fakeNetNumber, header.IPv4Any); err != nil { + t.Fatalf("AddAddress(%v, %v) failed: %v", fakeNetNumber, header.IPv4Any, err) + } + r, err := s.FindRoute(1, header.IPv4Any, header.IPv4Broadcast, fakeNetNumber) + if err != nil { + t.Fatalf("FindRoute(1, %v, %v, %v) failed: %v", header.IPv4Any, header.IPv4Broadcast, fakeNetNumber, err) + } + + if r.LocalAddress != header.IPv4Any { + t.Errorf("Bad local address: got %v, want = %v", r.LocalAddress, header.IPv4Any) + } + + if r.RemoteAddress != header.IPv4Broadcast { + t.Errorf("Bad remote address: got %v, want = %v", r.RemoteAddress, header.IPv4Broadcast) + } + + // If the NIC doesn't exist, it won't work. + if _, err := s.FindRoute(2, header.IPv4Any, header.IPv4Broadcast, fakeNetNumber); err != tcpip.ErrNoRoute { + t.Fatalf("got FindRoute(2, %v, %v, %v) = %v want = %v", header.IPv4Any, header.IPv4Broadcast, fakeNetNumber, err, tcpip.ErrNoRoute) + } +} + // Set the subnet, then check that packet is delivered. func TestSubnetAcceptsMatchingPacket(t *testing.T) { s := stack.New([]string{"fakeNet"}, nil, stack.Options{}) @@ -849,7 +886,7 @@ func TestGetMainNICAddressAddPrimaryNonPrimary(t *testing.T) { if !ok { t.Fatalf("GetMainNICAddress: got address = %v, wanted any in {%v}", gotAddress, primaryAddrAdded) } - if expectedSubnet != gotSubnet { + if gotSubnet != expectedSubnet { t.Fatalf("GetMainNICAddress: got subnet = %v, wanted %v", gotSubnet, expectedSubnet) } } |