mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Use brodcast MAC for broadcast IPv4 packets
When sending packets to a known network's broadcast address, use the broadcast MAC address. Test: - stack_test.TestOutgoingSubnetBroadcast - udp_test.TestOutgoingSubnetBroadcast PiperOrigin-RevId: 324062407
This commit is contained in:
committed by
gVisor bot
parent
bc8201d01b
commit
b00858d075
@@ -110,6 +110,7 @@ go_test(
|
||||
"//pkg/tcpip/transport/udp",
|
||||
"//pkg/waiter",
|
||||
"@com_github_google_go_cmp//cmp:go_default_library",
|
||||
"@com_github_google_go_cmp//cmp/cmpopts:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -48,6 +48,10 @@ type Route struct {
|
||||
|
||||
// Loop controls where WritePacket should send packets.
|
||||
Loop PacketLooping
|
||||
|
||||
// directedBroadcast indicates whether this route is sending a directed
|
||||
// broadcast packet.
|
||||
directedBroadcast bool
|
||||
}
|
||||
|
||||
// makeRoute initializes a new route. It takes ownership of the provided
|
||||
@@ -275,6 +279,12 @@ func (r *Route) Stack() *Stack {
|
||||
return r.ref.stack()
|
||||
}
|
||||
|
||||
// IsBroadcast returns true if the route is to send a broadcast packet.
|
||||
func (r *Route) IsBroadcast() bool {
|
||||
// Only IPv4 has a notion of broadcast.
|
||||
return r.directedBroadcast || r.RemoteAddress == header.IPv4Broadcast
|
||||
}
|
||||
|
||||
// ReverseRoute returns new route with given source and destination address.
|
||||
func (r *Route) ReverseRoute(src tcpip.Address, dst tcpip.Address) Route {
|
||||
return Route{
|
||||
|
||||
@@ -1284,9 +1284,9 @@ func (s *Stack) FindRoute(id tcpip.NICID, localAddr, remoteAddr tcpip.Address, n
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
isBroadcast := remoteAddr == header.IPv4Broadcast
|
||||
isLocalBroadcast := remoteAddr == header.IPv4Broadcast
|
||||
isMulticast := header.IsV4MulticastAddress(remoteAddr) || header.IsV6MulticastAddress(remoteAddr)
|
||||
needRoute := !(isBroadcast || isMulticast || header.IsV6LinkLocalAddress(remoteAddr))
|
||||
needRoute := !(isLocalBroadcast || isMulticast || header.IsV6LinkLocalAddress(remoteAddr))
|
||||
if id != 0 && !needRoute {
|
||||
if nic, ok := s.nics[id]; ok && nic.enabled() {
|
||||
if ref := s.getRefEP(nic, localAddr, remoteAddr, netProto); ref != nil {
|
||||
@@ -1307,9 +1307,16 @@ func (s *Stack) FindRoute(id tcpip.NICID, localAddr, remoteAddr tcpip.Address, n
|
||||
}
|
||||
|
||||
r := makeRoute(netProto, ref.ep.ID().LocalAddress, remoteAddr, nic.linkEP.LinkAddress(), ref, s.handleLocal && !nic.isLoopback(), multicastLoop && !nic.isLoopback())
|
||||
if needRoute {
|
||||
r.NextHop = route.Gateway
|
||||
r.directedBroadcast = route.Destination.IsBroadcast(remoteAddr)
|
||||
|
||||
if len(route.Gateway) > 0 {
|
||||
if needRoute {
|
||||
r.NextHop = route.Gateway
|
||||
}
|
||||
} else if r.directedBroadcast {
|
||||
r.RemoteLinkAddress = header.EthernetBroadcastAddress
|
||||
}
|
||||
|
||||
return r, nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
"gvisor.dev/gvisor/pkg/rand"
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/buffer"
|
||||
@@ -3418,3 +3419,225 @@ func TestStackSendBufferSizeOption(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestOutgoingSubnetBroadcast(t *testing.T) {
|
||||
const (
|
||||
unspecifiedNICID = 0
|
||||
nicID1 = 1
|
||||
)
|
||||
|
||||
defaultAddr := tcpip.AddressWithPrefix{
|
||||
Address: header.IPv4Any,
|
||||
PrefixLen: 0,
|
||||
}
|
||||
defaultSubnet := defaultAddr.Subnet()
|
||||
ipv4Addr := tcpip.AddressWithPrefix{
|
||||
Address: "\xc0\xa8\x01\x3a",
|
||||
PrefixLen: 24,
|
||||
}
|
||||
ipv4Subnet := ipv4Addr.Subnet()
|
||||
ipv4SubnetBcast := ipv4Subnet.Broadcast()
|
||||
ipv4Gateway := tcpip.Address("\xc0\xa8\x01\x01")
|
||||
ipv4AddrPrefix31 := tcpip.AddressWithPrefix{
|
||||
Address: "\xc0\xa8\x01\x3a",
|
||||
PrefixLen: 31,
|
||||
}
|
||||
ipv4Subnet31 := ipv4AddrPrefix31.Subnet()
|
||||
ipv4Subnet31Bcast := ipv4Subnet31.Broadcast()
|
||||
ipv4AddrPrefix32 := tcpip.AddressWithPrefix{
|
||||
Address: "\xc0\xa8\x01\x3a",
|
||||
PrefixLen: 32,
|
||||
}
|
||||
ipv4Subnet32 := ipv4AddrPrefix32.Subnet()
|
||||
ipv4Subnet32Bcast := ipv4Subnet32.Broadcast()
|
||||
ipv6Addr := tcpip.AddressWithPrefix{
|
||||
Address: "\x20\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
|
||||
PrefixLen: 64,
|
||||
}
|
||||
ipv6Subnet := ipv6Addr.Subnet()
|
||||
ipv6SubnetBcast := ipv6Subnet.Broadcast()
|
||||
remNetAddr := tcpip.AddressWithPrefix{
|
||||
Address: "\x64\x0a\x7b\x18",
|
||||
PrefixLen: 24,
|
||||
}
|
||||
remNetSubnet := remNetAddr.Subnet()
|
||||
remNetSubnetBcast := remNetSubnet.Broadcast()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
nicAddr tcpip.ProtocolAddress
|
||||
routes []tcpip.Route
|
||||
remoteAddr tcpip.Address
|
||||
expectedRoute stack.Route
|
||||
}{
|
||||
// Broadcast to a locally attached subnet populates the broadcast MAC.
|
||||
{
|
||||
name: "IPv4 Broadcast to local subnet",
|
||||
nicAddr: tcpip.ProtocolAddress{
|
||||
Protocol: header.IPv4ProtocolNumber,
|
||||
AddressWithPrefix: ipv4Addr,
|
||||
},
|
||||
routes: []tcpip.Route{
|
||||
{
|
||||
Destination: ipv4Subnet,
|
||||
NIC: nicID1,
|
||||
},
|
||||
},
|
||||
remoteAddr: ipv4SubnetBcast,
|
||||
expectedRoute: stack.Route{
|
||||
LocalAddress: ipv4Addr.Address,
|
||||
RemoteAddress: ipv4SubnetBcast,
|
||||
RemoteLinkAddress: header.EthernetBroadcastAddress,
|
||||
NetProto: header.IPv4ProtocolNumber,
|
||||
Loop: stack.PacketOut,
|
||||
},
|
||||
},
|
||||
// Broadcast to a locally attached /31 subnet does not populate the
|
||||
// broadcast MAC.
|
||||
{
|
||||
name: "IPv4 Broadcast to local /31 subnet",
|
||||
nicAddr: tcpip.ProtocolAddress{
|
||||
Protocol: header.IPv4ProtocolNumber,
|
||||
AddressWithPrefix: ipv4AddrPrefix31,
|
||||
},
|
||||
routes: []tcpip.Route{
|
||||
{
|
||||
Destination: ipv4Subnet31,
|
||||
NIC: nicID1,
|
||||
},
|
||||
},
|
||||
remoteAddr: ipv4Subnet31Bcast,
|
||||
expectedRoute: stack.Route{
|
||||
LocalAddress: ipv4AddrPrefix31.Address,
|
||||
RemoteAddress: ipv4Subnet31Bcast,
|
||||
NetProto: header.IPv4ProtocolNumber,
|
||||
Loop: stack.PacketOut,
|
||||
},
|
||||
},
|
||||
// Broadcast to a locally attached /32 subnet does not populate the
|
||||
// broadcast MAC.
|
||||
{
|
||||
name: "IPv4 Broadcast to local /32 subnet",
|
||||
nicAddr: tcpip.ProtocolAddress{
|
||||
Protocol: header.IPv4ProtocolNumber,
|
||||
AddressWithPrefix: ipv4AddrPrefix32,
|
||||
},
|
||||
routes: []tcpip.Route{
|
||||
{
|
||||
Destination: ipv4Subnet32,
|
||||
NIC: nicID1,
|
||||
},
|
||||
},
|
||||
remoteAddr: ipv4Subnet32Bcast,
|
||||
expectedRoute: stack.Route{
|
||||
LocalAddress: ipv4AddrPrefix32.Address,
|
||||
RemoteAddress: ipv4Subnet32Bcast,
|
||||
NetProto: header.IPv4ProtocolNumber,
|
||||
Loop: stack.PacketOut,
|
||||
},
|
||||
},
|
||||
// IPv6 has no notion of a broadcast.
|
||||
{
|
||||
name: "IPv6 'Broadcast' to local subnet",
|
||||
nicAddr: tcpip.ProtocolAddress{
|
||||
Protocol: header.IPv6ProtocolNumber,
|
||||
AddressWithPrefix: ipv6Addr,
|
||||
},
|
||||
routes: []tcpip.Route{
|
||||
{
|
||||
Destination: ipv6Subnet,
|
||||
NIC: nicID1,
|
||||
},
|
||||
},
|
||||
remoteAddr: ipv6SubnetBcast,
|
||||
expectedRoute: stack.Route{
|
||||
LocalAddress: ipv6Addr.Address,
|
||||
RemoteAddress: ipv6SubnetBcast,
|
||||
NetProto: header.IPv6ProtocolNumber,
|
||||
Loop: stack.PacketOut,
|
||||
},
|
||||
},
|
||||
// Broadcast to a remote subnet in the route table is send to the next-hop
|
||||
// gateway.
|
||||
{
|
||||
name: "IPv4 Broadcast to remote subnet",
|
||||
nicAddr: tcpip.ProtocolAddress{
|
||||
Protocol: header.IPv4ProtocolNumber,
|
||||
AddressWithPrefix: ipv4Addr,
|
||||
},
|
||||
routes: []tcpip.Route{
|
||||
{
|
||||
Destination: remNetSubnet,
|
||||
Gateway: ipv4Gateway,
|
||||
NIC: nicID1,
|
||||
},
|
||||
},
|
||||
remoteAddr: remNetSubnetBcast,
|
||||
expectedRoute: stack.Route{
|
||||
LocalAddress: ipv4Addr.Address,
|
||||
RemoteAddress: remNetSubnetBcast,
|
||||
NextHop: ipv4Gateway,
|
||||
NetProto: header.IPv4ProtocolNumber,
|
||||
Loop: stack.PacketOut,
|
||||
},
|
||||
},
|
||||
// Broadcast to an unknown subnet follows the default route. Note that this
|
||||
// is essentially just routing an unknown destination IP, because w/o any
|
||||
// subnet prefix information a subnet broadcast address is just a normal IP.
|
||||
{
|
||||
name: "IPv4 Broadcast to unknown subnet",
|
||||
nicAddr: tcpip.ProtocolAddress{
|
||||
Protocol: header.IPv4ProtocolNumber,
|
||||
AddressWithPrefix: ipv4Addr,
|
||||
},
|
||||
routes: []tcpip.Route{
|
||||
{
|
||||
Destination: defaultSubnet,
|
||||
Gateway: ipv4Gateway,
|
||||
NIC: nicID1,
|
||||
},
|
||||
},
|
||||
remoteAddr: remNetSubnetBcast,
|
||||
expectedRoute: stack.Route{
|
||||
LocalAddress: ipv4Addr.Address,
|
||||
RemoteAddress: remNetSubnetBcast,
|
||||
NextHop: ipv4Gateway,
|
||||
NetProto: header.IPv4ProtocolNumber,
|
||||
Loop: stack.PacketOut,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
s := stack.New(stack.Options{
|
||||
NetworkProtocols: []stack.NetworkProtocol{ipv4.NewProtocol(), ipv6.NewProtocol()},
|
||||
})
|
||||
ep := channel.New(0, defaultMTU, "")
|
||||
if err := s.CreateNIC(nicID1, ep); err != nil {
|
||||
t.Fatalf("CreateNIC(%d, _): %s", nicID1, err)
|
||||
}
|
||||
if err := s.AddProtocolAddress(nicID1, test.nicAddr); err != nil {
|
||||
t.Fatalf("AddProtocolAddress(%d, %+v): %s", nicID1, test.nicAddr, err)
|
||||
}
|
||||
|
||||
s.SetRouteTable(test.routes)
|
||||
|
||||
var netProto tcpip.NetworkProtocolNumber
|
||||
switch l := len(test.remoteAddr); l {
|
||||
case header.IPv4AddressSize:
|
||||
netProto = header.IPv4ProtocolNumber
|
||||
case header.IPv6AddressSize:
|
||||
netProto = header.IPv6ProtocolNumber
|
||||
default:
|
||||
t.Fatalf("got unexpected address length = %d bytes", l)
|
||||
}
|
||||
|
||||
if r, err := s.FindRoute(unspecifiedNICID, "" /* localAddr */, test.remoteAddr, netProto, false /* multicastLoop */); err != nil {
|
||||
t.Fatalf("FindRoute(%d, '', %s, %d): %s", unspecifiedNICID, test.remoteAddr, netProto, err)
|
||||
} else if diff := cmp.Diff(r, test.expectedRoute, cmpopts.IgnoreUnexported(r)); diff != "" {
|
||||
t.Errorf("route mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +43,9 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/waiter"
|
||||
)
|
||||
|
||||
// Using header.IPv4AddressSize would cause an import cycle.
|
||||
const ipv4AddressSize = 4
|
||||
|
||||
// Error represents an error in the netstack error space. Using a special type
|
||||
// ensures that errors outside of this space are not accidentally introduced.
|
||||
//
|
||||
@@ -320,6 +323,29 @@ func (s *Subnet) Broadcast() Address {
|
||||
return Address(addr)
|
||||
}
|
||||
|
||||
// IsBroadcast returns true if the address is considered a broadcast address.
|
||||
func (s *Subnet) IsBroadcast(address Address) bool {
|
||||
// Only IPv4 supports the notion of a broadcast address.
|
||||
if len(address) != ipv4AddressSize {
|
||||
return false
|
||||
}
|
||||
|
||||
// Normally, we would just compare address with the subnet's broadcast
|
||||
// address but there is an exception where a simple comparison is not
|
||||
// correct. This exception is for /31 and /32 IPv4 subnets where all
|
||||
// addresses are considered valid host addresses.
|
||||
//
|
||||
// For /31 subnets, the case is easy. RFC 3021 Section 2.1 states that
|
||||
// both addresses in a /31 subnet "MUST be interpreted as host addresses."
|
||||
//
|
||||
// For /32, the case is a bit more vague. RFC 3021 makes no mention of /32
|
||||
// subnets. However, the same reasoning applies - if an exception is not
|
||||
// made, then there do not exist any host addresses in a /32 subnet. RFC
|
||||
// 4632 Section 3.1 also vaguely implies this interpretation by referring
|
||||
// to addresses in /32 subnets as "host routes."
|
||||
return s.Prefix() <= 30 && s.Broadcast() == address
|
||||
}
|
||||
|
||||
// Equal returns true if s equals o.
|
||||
//
|
||||
// Needed to use cmp.Equal on Subnet as its fields are unexported.
|
||||
|
||||
@@ -483,10 +483,6 @@ func (e *endpoint) write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, <-c
|
||||
nicID = e.BindNICID
|
||||
}
|
||||
|
||||
if to.Addr == header.IPv4Broadcast && !e.broadcast {
|
||||
return 0, nil, tcpip.ErrBroadcastDisabled
|
||||
}
|
||||
|
||||
dst, netProto, err := e.checkV4MappedLocked(*to)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
@@ -503,6 +499,10 @@ func (e *endpoint) write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, <-c
|
||||
resolve = route.Resolve
|
||||
}
|
||||
|
||||
if !e.broadcast && route.IsBroadcast() {
|
||||
return 0, nil, tcpip.ErrBroadcastDisabled
|
||||
}
|
||||
|
||||
if route.IsResolutionRequired() {
|
||||
if ch, err := resolve(nil); err != nil {
|
||||
if err == tcpip.ErrWouldBlock {
|
||||
|
||||
@@ -2142,3 +2142,192 @@ func (c *testContext) checkEndpointReadStats(incr uint64, want tcpip.TransportEn
|
||||
c.t.Errorf("Endpoint stats not matching for error %s got %+v want %+v", err, got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOutgoingSubnetBroadcast(t *testing.T) {
|
||||
const nicID1 = 1
|
||||
|
||||
ipv4Addr := tcpip.AddressWithPrefix{
|
||||
Address: "\xc0\xa8\x01\x3a",
|
||||
PrefixLen: 24,
|
||||
}
|
||||
ipv4Subnet := ipv4Addr.Subnet()
|
||||
ipv4SubnetBcast := ipv4Subnet.Broadcast()
|
||||
ipv4Gateway := tcpip.Address("\xc0\xa8\x01\x01")
|
||||
ipv4AddrPrefix31 := tcpip.AddressWithPrefix{
|
||||
Address: "\xc0\xa8\x01\x3a",
|
||||
PrefixLen: 31,
|
||||
}
|
||||
ipv4Subnet31 := ipv4AddrPrefix31.Subnet()
|
||||
ipv4Subnet31Bcast := ipv4Subnet31.Broadcast()
|
||||
ipv4AddrPrefix32 := tcpip.AddressWithPrefix{
|
||||
Address: "\xc0\xa8\x01\x3a",
|
||||
PrefixLen: 32,
|
||||
}
|
||||
ipv4Subnet32 := ipv4AddrPrefix32.Subnet()
|
||||
ipv4Subnet32Bcast := ipv4Subnet32.Broadcast()
|
||||
ipv6Addr := tcpip.AddressWithPrefix{
|
||||
Address: "\x20\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
|
||||
PrefixLen: 64,
|
||||
}
|
||||
ipv6Subnet := ipv6Addr.Subnet()
|
||||
ipv6SubnetBcast := ipv6Subnet.Broadcast()
|
||||
remNetAddr := tcpip.AddressWithPrefix{
|
||||
Address: "\x64\x0a\x7b\x18",
|
||||
PrefixLen: 24,
|
||||
}
|
||||
remNetSubnet := remNetAddr.Subnet()
|
||||
remNetSubnetBcast := remNetSubnet.Broadcast()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
nicAddr tcpip.ProtocolAddress
|
||||
routes []tcpip.Route
|
||||
remoteAddr tcpip.Address
|
||||
requiresBroadcastOpt bool
|
||||
}{
|
||||
{
|
||||
name: "IPv4 Broadcast to local subnet",
|
||||
nicAddr: tcpip.ProtocolAddress{
|
||||
Protocol: header.IPv4ProtocolNumber,
|
||||
AddressWithPrefix: ipv4Addr,
|
||||
},
|
||||
routes: []tcpip.Route{
|
||||
{
|
||||
Destination: ipv4Subnet,
|
||||
NIC: nicID1,
|
||||
},
|
||||
},
|
||||
remoteAddr: ipv4SubnetBcast,
|
||||
requiresBroadcastOpt: true,
|
||||
},
|
||||
{
|
||||
name: "IPv4 Broadcast to local /31 subnet",
|
||||
nicAddr: tcpip.ProtocolAddress{
|
||||
Protocol: header.IPv4ProtocolNumber,
|
||||
AddressWithPrefix: ipv4AddrPrefix31,
|
||||
},
|
||||
routes: []tcpip.Route{
|
||||
{
|
||||
Destination: ipv4Subnet31,
|
||||
NIC: nicID1,
|
||||
},
|
||||
},
|
||||
remoteAddr: ipv4Subnet31Bcast,
|
||||
requiresBroadcastOpt: false,
|
||||
},
|
||||
{
|
||||
name: "IPv4 Broadcast to local /32 subnet",
|
||||
nicAddr: tcpip.ProtocolAddress{
|
||||
Protocol: header.IPv4ProtocolNumber,
|
||||
AddressWithPrefix: ipv4AddrPrefix32,
|
||||
},
|
||||
routes: []tcpip.Route{
|
||||
{
|
||||
Destination: ipv4Subnet32,
|
||||
NIC: nicID1,
|
||||
},
|
||||
},
|
||||
remoteAddr: ipv4Subnet32Bcast,
|
||||
requiresBroadcastOpt: false,
|
||||
},
|
||||
// IPv6 has no notion of a broadcast.
|
||||
{
|
||||
name: "IPv6 'Broadcast' to local subnet",
|
||||
nicAddr: tcpip.ProtocolAddress{
|
||||
Protocol: header.IPv6ProtocolNumber,
|
||||
AddressWithPrefix: ipv6Addr,
|
||||
},
|
||||
routes: []tcpip.Route{
|
||||
{
|
||||
Destination: ipv6Subnet,
|
||||
NIC: nicID1,
|
||||
},
|
||||
},
|
||||
remoteAddr: ipv6SubnetBcast,
|
||||
requiresBroadcastOpt: false,
|
||||
},
|
||||
{
|
||||
name: "IPv4 Broadcast to remote subnet",
|
||||
nicAddr: tcpip.ProtocolAddress{
|
||||
Protocol: header.IPv4ProtocolNumber,
|
||||
AddressWithPrefix: ipv4Addr,
|
||||
},
|
||||
routes: []tcpip.Route{
|
||||
{
|
||||
Destination: remNetSubnet,
|
||||
Gateway: ipv4Gateway,
|
||||
NIC: nicID1,
|
||||
},
|
||||
},
|
||||
remoteAddr: remNetSubnetBcast,
|
||||
requiresBroadcastOpt: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
s := stack.New(stack.Options{
|
||||
NetworkProtocols: []stack.NetworkProtocol{ipv4.NewProtocol(), ipv6.NewProtocol()},
|
||||
|
||||
TransportProtocols: []stack.TransportProtocol{udp.NewProtocol()},
|
||||
})
|
||||
e := channel.New(0, defaultMTU, "")
|
||||
if err := s.CreateNIC(nicID1, e); err != nil {
|
||||
t.Fatalf("CreateNIC(%d, _): %s", nicID1, err)
|
||||
}
|
||||
if err := s.AddProtocolAddress(nicID1, test.nicAddr); err != nil {
|
||||
t.Fatalf("AddProtocolAddress(%d, %+v): %s", nicID1, test.nicAddr, err)
|
||||
}
|
||||
|
||||
s.SetRouteTable(test.routes)
|
||||
|
||||
var netProto tcpip.NetworkProtocolNumber
|
||||
switch l := len(test.remoteAddr); l {
|
||||
case header.IPv4AddressSize:
|
||||
netProto = header.IPv4ProtocolNumber
|
||||
case header.IPv6AddressSize:
|
||||
netProto = header.IPv6ProtocolNumber
|
||||
default:
|
||||
t.Fatalf("got unexpected address length = %d bytes", l)
|
||||
}
|
||||
|
||||
wq := waiter.Queue{}
|
||||
ep, err := s.NewEndpoint(udp.ProtocolNumber, netProto, &wq)
|
||||
if err != nil {
|
||||
t.Fatalf("NewEndpoint(%d, %d, _): %s", udp.ProtocolNumber, netProto, err)
|
||||
}
|
||||
defer ep.Close()
|
||||
|
||||
data := tcpip.SlicePayload([]byte{1, 2, 3, 4})
|
||||
to := tcpip.FullAddress{
|
||||
Addr: test.remoteAddr,
|
||||
Port: 80,
|
||||
}
|
||||
opts := tcpip.WriteOptions{To: &to}
|
||||
expectedErrWithoutBcastOpt := tcpip.ErrBroadcastDisabled
|
||||
if !test.requiresBroadcastOpt {
|
||||
expectedErrWithoutBcastOpt = nil
|
||||
}
|
||||
|
||||
if n, _, err := ep.Write(data, opts); err != expectedErrWithoutBcastOpt {
|
||||
t.Fatalf("got ep.Write(_, _) = (%d, _, %v), want = (_, _, %v)", n, err, expectedErrWithoutBcastOpt)
|
||||
}
|
||||
|
||||
if err := ep.SetSockOptBool(tcpip.BroadcastOption, true); err != nil {
|
||||
t.Fatalf("got SetSockOptBool(BroadcastOption, true): %s", err)
|
||||
}
|
||||
|
||||
if n, _, err := ep.Write(data, opts); err != nil {
|
||||
t.Fatalf("got ep.Write(_, _) = (%d, _, %s), want = (_, _, nil)", n, err)
|
||||
}
|
||||
|
||||
if err := ep.SetSockOptBool(tcpip.BroadcastOption, false); err != nil {
|
||||
t.Fatalf("got SetSockOptBool(BroadcastOption, false): %s", err)
|
||||
}
|
||||
|
||||
if n, _, err := ep.Write(data, opts); err != expectedErrWithoutBcastOpt {
|
||||
t.Fatalf("got ep.Write(_, _) = (%d, _, %v), want = (_, _, %v)", n, err, expectedErrWithoutBcastOpt)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user