mirror of
https://github.com/golang/net.git
synced 2026-03-31 18:37:08 +09:00
go.net/ipv4: fix sprious lookahead on IPConn-based PacketConn
Also improves test coverage for both payload and datagram I/O. R=golang-dev, dave CC=golang-dev https://golang.org/cl/7304091
This commit is contained in:
@@ -44,27 +44,24 @@ var (
|
||||
}
|
||||
// TODO(mikio): Add platform dependent wire header formats when
|
||||
// we support new platforms.
|
||||
|
||||
testHeader = &ipv4.Header{
|
||||
Version: ipv4.Version,
|
||||
Len: ipv4.HeaderLen,
|
||||
TOS: 1,
|
||||
TotalLen: 0xbeef,
|
||||
ID: 0xcafe,
|
||||
FragOff: 1500,
|
||||
TTL: 255,
|
||||
Protocol: 1,
|
||||
Checksum: 0xdead,
|
||||
Src: net.IPv4(172, 16, 254, 254),
|
||||
Dst: net.IPv4(192, 168, 0, 1),
|
||||
}
|
||||
)
|
||||
|
||||
func testHeader() *ipv4.Header {
|
||||
h := &ipv4.Header{}
|
||||
h.Version = ipv4.Version
|
||||
h.Len = ipv4.HeaderLen
|
||||
h.TOS = 1
|
||||
h.TotalLen = 0xbeef
|
||||
h.ID = 0xcafe
|
||||
h.FragOff = 1500
|
||||
h.TTL = 255
|
||||
h.Protocol = 1
|
||||
h.Checksum = 0xdead
|
||||
h.Src = net.IPv4(172, 16, 254, 254)
|
||||
h.Dst = net.IPv4(192, 168, 0, 1)
|
||||
return h
|
||||
}
|
||||
|
||||
func TestMarshalHeader(t *testing.T) {
|
||||
th := testHeader()
|
||||
b, err := th.Marshal()
|
||||
b, err := testHeader.Marshal()
|
||||
if err != nil {
|
||||
t.Fatalf("ipv4.Header.Marshal failed: %v", err)
|
||||
}
|
||||
@@ -92,8 +89,7 @@ func TestParseHeader(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("ipv4.ParseHeader failed: %v", err)
|
||||
}
|
||||
th := testHeader()
|
||||
if !reflect.DeepEqual(h, th) {
|
||||
t.Fatalf("ipv4.ParseHeader failed: %#v not equal %#v", h, th)
|
||||
if !reflect.DeepEqual(h, testHeader) {
|
||||
t.Fatalf("ipv4.ParseHeader failed: %#v not equal %#v", h, testHeader)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,43 +5,117 @@
|
||||
package ipv4_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"flag"
|
||||
)
|
||||
|
||||
var testExternal = flag.Bool("external", true, "allow use of external networks during long test")
|
||||
|
||||
func newICMPEchoRequest(id, seqnum, msglen int, filler []byte) []byte {
|
||||
b := newICMPInfoMessage(id, seqnum, msglen, filler)
|
||||
b[0] = 8
|
||||
// calculate ICMP checksum
|
||||
cklen := len(b)
|
||||
s := uint32(0)
|
||||
for i := 0; i < cklen-1; i += 2 {
|
||||
s += uint32(b[i+1])<<8 | uint32(b[i])
|
||||
}
|
||||
if cklen&1 == 1 {
|
||||
s += uint32(b[cklen-1])
|
||||
}
|
||||
s = (s >> 16) + (s & 0xffff)
|
||||
s = s + (s >> 16)
|
||||
// place checksum back in header; using ^= avoids the
|
||||
// assumption the checksum bytes are zero
|
||||
b[2] ^= byte(^s & 0xff)
|
||||
b[3] ^= byte(^s >> 8)
|
||||
return b
|
||||
const (
|
||||
icmpv4EchoRequest = 8
|
||||
icmpv4EchoReply = 0
|
||||
icmpv6EchoRequest = 128
|
||||
icmpv6EchoReply = 129
|
||||
)
|
||||
|
||||
// icmpMessage represents an ICMP message.
|
||||
type icmpMessage struct {
|
||||
Type int // type
|
||||
Code int // code
|
||||
Checksum int // checksum
|
||||
Body icmpMessageBody // body
|
||||
}
|
||||
|
||||
func newICMPInfoMessage(id, seqnum, msglen int, filler []byte) []byte {
|
||||
b := make([]byte, msglen)
|
||||
copy(b[8:], bytes.Repeat(filler, (msglen-8)/len(filler)+1))
|
||||
b[0] = 0 // type
|
||||
b[1] = 0 // code
|
||||
b[2] = 0 // checksum
|
||||
b[3] = 0 // checksum
|
||||
b[4] = byte(id >> 8) // identifier
|
||||
b[5] = byte(id & 0xff) // identifier
|
||||
b[6] = byte(seqnum >> 8) // sequence number
|
||||
b[7] = byte(seqnum & 0xff) // sequence number
|
||||
return b
|
||||
// icmpMessageBody represents an ICMP message body.
|
||||
type icmpMessageBody interface {
|
||||
Len() int
|
||||
Marshal() ([]byte, error)
|
||||
}
|
||||
|
||||
// Marshal returns the binary enconding of the ICMP echo request or
|
||||
// reply message m.
|
||||
func (m *icmpMessage) Marshal() ([]byte, error) {
|
||||
b := []byte{byte(m.Type), byte(m.Code), 0, 0}
|
||||
if m.Body != nil && m.Body.Len() != 0 {
|
||||
mb, err := m.Body.Marshal()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b = append(b, mb...)
|
||||
}
|
||||
switch m.Type {
|
||||
case icmpv6EchoRequest, icmpv6EchoReply:
|
||||
return b, nil
|
||||
}
|
||||
csumcv := len(b) - 1 // checksum coverage
|
||||
s := uint32(0)
|
||||
for i := 0; i < csumcv; i += 2 {
|
||||
s += uint32(b[i+1])<<8 | uint32(b[i])
|
||||
}
|
||||
if csumcv&1 == 0 {
|
||||
s += uint32(b[csumcv])
|
||||
}
|
||||
s = s>>16 + s&0xffff
|
||||
s = s + s>>16
|
||||
// Place checksum back in header; using ^= avoids the
|
||||
// assumption the checksum bytes are zero.
|
||||
b[2] ^= byte(^s & 0xff)
|
||||
b[3] ^= byte(^s >> 8)
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// parseICMPMessage parses b as an ICMP message.
|
||||
func parseICMPMessage(b []byte) (*icmpMessage, error) {
|
||||
msglen := len(b)
|
||||
if msglen < 4 {
|
||||
return nil, errors.New("message too short")
|
||||
}
|
||||
m := &icmpMessage{Type: int(b[0]), Code: int(b[1]), Checksum: int(b[2])<<8 | int(b[3])}
|
||||
if msglen > 4 {
|
||||
var err error
|
||||
switch m.Type {
|
||||
case icmpv4EchoRequest, icmpv4EchoReply, icmpv6EchoRequest, icmpv6EchoReply:
|
||||
m.Body, err = parseICMPEcho(b[4:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// imcpEcho represenets an ICMP echo request or reply message body.
|
||||
type icmpEcho struct {
|
||||
ID int // identifier
|
||||
Seq int // sequence number
|
||||
Data []byte // data
|
||||
}
|
||||
|
||||
func (p *icmpEcho) Len() int {
|
||||
if p == nil {
|
||||
return 0
|
||||
}
|
||||
return 4 + len(p.Data)
|
||||
}
|
||||
|
||||
// Marshal returns the binary enconding of the ICMP echo request or
|
||||
// reply message body p.
|
||||
func (p *icmpEcho) Marshal() ([]byte, error) {
|
||||
b := make([]byte, 4+len(p.Data))
|
||||
b[0], b[1] = byte(p.ID>>8), byte(p.ID&0xff)
|
||||
b[2], b[3] = byte(p.Seq>>8), byte(p.Seq&0xff)
|
||||
copy(b[4:], p.Data)
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// parseICMPEcho parses b as an ICMP echo request or reply message
|
||||
// body.
|
||||
func parseICMPEcho(b []byte) (*icmpEcho, error) {
|
||||
bodylen := len(b)
|
||||
p := &icmpEcho{ID: int(b[0])<<8 | int(b[1]), Seq: int(b[2])<<8 | int(b[3])}
|
||||
if bodylen > 4 {
|
||||
p.Data = make([]byte, bodylen-4)
|
||||
copy(p.Data, b[4:])
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
@@ -13,77 +13,70 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// runPayloadTransponder transmits IPv4 datagram payloads to the
|
||||
// writeThenReadPayload transmits IPv4 datagram payloads to the
|
||||
// loopback address or interface and captures the loopback'd datagram
|
||||
// payloads.
|
||||
func runPayloadTransponder(t *testing.T, c *ipv4.PacketConn, wb []byte, dst net.Addr) {
|
||||
cf := ipv4.FlagTTL | ipv4.FlagDst | ipv4.FlagInterface
|
||||
func writeThenReadPayload(t *testing.T, i int, c *ipv4.PacketConn, wb []byte, dst net.Addr) []byte {
|
||||
rb := make([]byte, 1500)
|
||||
for i, toggle := range []bool{true, false, true} {
|
||||
if err := c.SetControlMessage(cf, toggle); err != nil {
|
||||
t.Fatalf("ipv4.PacketConn.SetControlMessage failed: %v", err)
|
||||
}
|
||||
c.SetTOS(i + 1)
|
||||
var ip net.IP
|
||||
switch v := dst.(type) {
|
||||
case *net.UDPAddr:
|
||||
ip = v.IP
|
||||
case *net.IPAddr:
|
||||
ip = v.IP
|
||||
}
|
||||
if ip.IsMulticast() {
|
||||
c.SetMulticastTTL(i + 1)
|
||||
} else {
|
||||
c.SetTTL(i + 1)
|
||||
}
|
||||
c.SetDeadline(time.Now().Add(100 * time.Millisecond))
|
||||
if _, err := c.WriteTo(wb, nil, dst); err != nil {
|
||||
t.Fatalf("ipv4.PacketConn.WriteTo failed: %v", err)
|
||||
}
|
||||
_, cm, _, err := c.ReadFrom(rb)
|
||||
if err != nil {
|
||||
t.Fatalf("ipv4.PacketConn.ReadFrom failed: %v", err)
|
||||
}
|
||||
t.Logf("rcvd cmsg: %v", cm)
|
||||
c.SetTOS(i + 1)
|
||||
var ip net.IP
|
||||
switch v := dst.(type) {
|
||||
case *net.UDPAddr:
|
||||
ip = v.IP
|
||||
case *net.IPAddr:
|
||||
ip = v.IP
|
||||
}
|
||||
if ip.IsMulticast() {
|
||||
c.SetMulticastTTL(i + 1)
|
||||
} else {
|
||||
c.SetTTL(i + 1)
|
||||
}
|
||||
c.SetDeadline(time.Now().Add(100 * time.Millisecond))
|
||||
if _, err := c.WriteTo(wb, nil, dst); err != nil {
|
||||
t.Fatalf("ipv4.PacketConn.WriteTo failed: %v", err)
|
||||
}
|
||||
n, cm, _, err := c.ReadFrom(rb)
|
||||
if err != nil {
|
||||
t.Fatalf("ipv4.PacketConn.ReadFrom failed: %v", err)
|
||||
}
|
||||
t.Logf("rcvd cmsg: %v", cm)
|
||||
return rb[:n]
|
||||
}
|
||||
|
||||
// runDatagramTransponder transmits ICMP for IPv4 datagrams to the
|
||||
// writeThenReadDatagram transmits ICMP for IPv4 datagrams to the
|
||||
// loopback address or interface and captures the response datagrams
|
||||
// from the protocol stack within the kernel.
|
||||
func runDatagramTransponder(t *testing.T, c *ipv4.RawConn, wb []byte, src, dst net.Addr) {
|
||||
cf := ipv4.FlagTTL | ipv4.FlagDst | ipv4.FlagInterface
|
||||
func writeThenReadDatagram(t *testing.T, i int, c *ipv4.RawConn, wb []byte, src, dst net.Addr) []byte {
|
||||
rb := make([]byte, ipv4.HeaderLen+len(wb))
|
||||
for i, toggle := range []bool{true, false, true} {
|
||||
if err := c.SetControlMessage(cf, toggle); err != nil {
|
||||
t.Fatalf("ipv4.RawConn.SetControlMessage failed: %v", err)
|
||||
}
|
||||
wh := &ipv4.Header{}
|
||||
wh.Version = ipv4.Version
|
||||
wh.Len = ipv4.HeaderLen
|
||||
wh.TOS = i + 1
|
||||
wh.TotalLen = ipv4.HeaderLen + len(wb)
|
||||
wh.TTL = i + 1
|
||||
wh.Protocol = 1
|
||||
if src != nil {
|
||||
wh.Src = src.(*net.IPAddr).IP
|
||||
}
|
||||
if dst != nil {
|
||||
wh.Dst = dst.(*net.IPAddr).IP
|
||||
}
|
||||
c.SetDeadline(time.Now().Add(100 * time.Millisecond))
|
||||
if err := c.WriteTo(wh, wb, nil); err != nil {
|
||||
t.Fatalf("ipv4.RawConn.WriteTo failed: %v", err)
|
||||
}
|
||||
rh, _, cm, err := c.ReadFrom(rb)
|
||||
if err != nil {
|
||||
t.Fatalf("ipv4.RawConn.ReadFrom failed: %v", err)
|
||||
}
|
||||
t.Logf("rcvd cmsg: %v", cm.String())
|
||||
t.Logf("rcvd hdr: %v", rh.String())
|
||||
wh := &ipv4.Header{
|
||||
Version: ipv4.Version,
|
||||
Len: ipv4.HeaderLen,
|
||||
TOS: i + 1,
|
||||
TotalLen: ipv4.HeaderLen + len(wb),
|
||||
TTL: i + 1,
|
||||
Protocol: 1,
|
||||
}
|
||||
if src != nil {
|
||||
wh.Src = src.(*net.IPAddr).IP
|
||||
}
|
||||
if dst != nil {
|
||||
wh.Dst = dst.(*net.IPAddr).IP
|
||||
}
|
||||
c.SetDeadline(time.Now().Add(100 * time.Millisecond))
|
||||
if err := c.WriteTo(wh, wb, nil); err != nil {
|
||||
t.Fatalf("ipv4.RawConn.WriteTo failed: %v", err)
|
||||
}
|
||||
rh, b, cm, err := c.ReadFrom(rb)
|
||||
if err != nil {
|
||||
t.Fatalf("ipv4.RawConn.ReadFrom failed: %v", err)
|
||||
}
|
||||
t.Logf("rcvd cmsg: %v", cm.String())
|
||||
t.Logf("rcvd hdr: %v", rh.String())
|
||||
return b
|
||||
}
|
||||
|
||||
// LoopbackInterface returns a logical network interface for loopback
|
||||
// tests.
|
||||
func loopbackInterface() *net.Interface {
|
||||
ift, err := net.Interfaces()
|
||||
if err != nil {
|
||||
@@ -97,12 +90,13 @@ func loopbackInterface() *net.Interface {
|
||||
return nil
|
||||
}
|
||||
|
||||
func isGoodForMulticast(ifi *net.Interface) (net.IP, bool) {
|
||||
if ifi.Flags&net.FlagUp == 0 {
|
||||
// isMulticastAvailable returns true if ifi is a multicast access
|
||||
// enabled network interface. It also returns a unicast IPv4 address
|
||||
// that can be used for listening on ifi.
|
||||
func isMulticastAvailable(ifi *net.Interface) (net.IP, bool) {
|
||||
if ifi.Flags&net.FlagUp == 0 || ifi.Flags&net.FlagMulticast == 0 {
|
||||
return nil, false
|
||||
}
|
||||
// We need a unicast IPv4 address that can be used to specify
|
||||
// the IPv4 multicast interface.
|
||||
ifat, err := ifi.Addrs()
|
||||
if err != nil {
|
||||
return nil, false
|
||||
@@ -126,8 +120,5 @@ func isGoodForMulticast(ifi *net.Interface) (net.IP, bool) {
|
||||
}
|
||||
break
|
||||
}
|
||||
if ip == nil {
|
||||
return nil, false
|
||||
}
|
||||
return ip, true
|
||||
}
|
||||
|
||||
@@ -45,7 +45,13 @@ func TestReadWriteMulticastIPPayloadUDP(t *testing.T) {
|
||||
if err := p.SetMulticastLoopback(true); err != nil {
|
||||
t.Fatalf("ipv4.PacketConn.SetMulticastLoopback failed: %v", err)
|
||||
}
|
||||
runPayloadTransponder(t, p, []byte("HELLO-R-U-THERE"), dst)
|
||||
cf := ipv4.FlagTTL | ipv4.FlagDst | ipv4.FlagInterface
|
||||
for i, toggle := range []bool{true, false, true} {
|
||||
if err := p.SetControlMessage(cf, toggle); err != nil {
|
||||
t.Fatalf("ipv4.PacketConn.SetControlMessage failed: %v", err)
|
||||
}
|
||||
writeThenReadPayload(t, i, p, []byte("HELLO-R-U-THERE"), dst)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadWriteMulticastIPPayloadICMP(t *testing.T) {
|
||||
@@ -81,9 +87,30 @@ func TestReadWriteMulticastIPPayloadICMP(t *testing.T) {
|
||||
if err := p.SetMulticastInterface(ifi); err != nil {
|
||||
t.Fatalf("ipv4.PacketConn.SetMulticastInterface failed: %v", err)
|
||||
}
|
||||
id := os.Getpid() & 0xffff
|
||||
pld := newICMPEchoRequest(id, 1, 128, []byte("HELLO-R-U-THERE"))
|
||||
runPayloadTransponder(t, p, pld, dst)
|
||||
cf := ipv4.FlagTTL | ipv4.FlagDst | ipv4.FlagInterface
|
||||
for i, toggle := range []bool{true, false, true} {
|
||||
wb, err := (&icmpMessage{
|
||||
Type: icmpv4EchoRequest, Code: 0,
|
||||
Body: &icmpEcho{
|
||||
ID: os.Getpid() & 0xffff, Seq: i + 1,
|
||||
Data: []byte("HELLO-R-U-THERE"),
|
||||
},
|
||||
}).Marshal()
|
||||
if err != nil {
|
||||
t.Fatalf("icmpMessage.Marshal failed: %v", err)
|
||||
}
|
||||
if err := p.SetControlMessage(cf, toggle); err != nil {
|
||||
t.Fatalf("ipv4.PacketConn.SetControlMessage failed: %v", err)
|
||||
}
|
||||
rb := writeThenReadPayload(t, i, p, wb, dst)
|
||||
m, err := parseICMPMessage(rb)
|
||||
if err != nil {
|
||||
t.Fatalf("parseICMPMessage failed: %v", err)
|
||||
}
|
||||
if m.Type != icmpv4EchoReply || m.Code != 0 {
|
||||
t.Fatalf("got type=%v, code=%v; expected type=%v, code=%v", m.Type, m.Code, icmpv4EchoReply, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadWriteMulticastIPDatagram(t *testing.T) {
|
||||
@@ -122,7 +149,28 @@ func TestReadWriteMulticastIPDatagram(t *testing.T) {
|
||||
if err := r.SetMulticastInterface(ifi); err != nil {
|
||||
t.Fatalf("ipv4.PacketConn.SetMulticastInterface failed: %v", err)
|
||||
}
|
||||
id := os.Getpid() & 0xffff
|
||||
pld := newICMPEchoRequest(id, 1, 128, []byte("HELLO-R-U-THERE"))
|
||||
runDatagramTransponder(t, r, pld, nil, dst)
|
||||
cf := ipv4.FlagTTL | ipv4.FlagDst | ipv4.FlagInterface
|
||||
for i, toggle := range []bool{true, false, true} {
|
||||
wb, err := (&icmpMessage{
|
||||
Type: icmpv4EchoRequest, Code: 0,
|
||||
Body: &icmpEcho{
|
||||
ID: os.Getpid() & 0xffff, Seq: i + 1,
|
||||
Data: []byte("HELLO-R-U-THERE"),
|
||||
},
|
||||
}).Marshal()
|
||||
if err != nil {
|
||||
t.Fatalf("icmpMessage.Marshal failed: %v", err)
|
||||
}
|
||||
if err := r.SetControlMessage(cf, toggle); err != nil {
|
||||
t.Fatalf("ipv4.RawConn.SetControlMessage failed: %v", err)
|
||||
}
|
||||
rb := writeThenReadDatagram(t, i, r, wb, nil, dst)
|
||||
m, err := parseICMPMessage(rb)
|
||||
if err != nil {
|
||||
t.Fatalf("parseICMPMessage failed: %v", err)
|
||||
}
|
||||
if m.Type != icmpv4EchoReply || m.Code != 0 {
|
||||
t.Fatalf("got type=%v, code=%v; expected type=%v, code=%v", m.Type, m.Code, icmpv4EchoReply, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ func TestUDPSingleConnWithMultipleGroupListeners(t *testing.T) {
|
||||
t.Fatalf("net.Interfaces failed: %v", err)
|
||||
}
|
||||
for i, ifi := range ift {
|
||||
if _, ok := isGoodForMulticast(&ifi); !ok {
|
||||
if _, ok := isMulticastAvailable(&ifi); !ok {
|
||||
continue
|
||||
}
|
||||
if err := p.JoinGroup(&ifi, tt.gaddr); err != nil {
|
||||
@@ -90,7 +90,7 @@ func TestUDPMultipleConnWithMultipleGroupListeners(t *testing.T) {
|
||||
t.Fatalf("net.Interfaces failed: %v", err)
|
||||
}
|
||||
for i, ifi := range ift {
|
||||
if _, ok := isGoodForMulticast(&ifi); !ok {
|
||||
if _, ok := isMulticastAvailable(&ifi); !ok {
|
||||
continue
|
||||
}
|
||||
for _, p := range ps {
|
||||
@@ -139,7 +139,7 @@ func TestIPSingleConnWithSingleGroupListener(t *testing.T) {
|
||||
t.Fatalf("net.Interfaces failed: %v", err)
|
||||
}
|
||||
for i, ifi := range ift {
|
||||
if _, ok := isGoodForMulticast(&ifi); !ok {
|
||||
if _, ok := isMulticastAvailable(&ifi); !ok {
|
||||
continue
|
||||
}
|
||||
if err := r.JoinGroup(&ifi, gaddr); err != nil {
|
||||
@@ -172,7 +172,7 @@ func TestUDPPerInterfaceSingleConnWithSingleGroupListener(t *testing.T) {
|
||||
t.Fatalf("net.Interfaces failed: %v", err)
|
||||
}
|
||||
for i, ifi := range ift {
|
||||
ip, ok := isGoodForMulticast(&ifi)
|
||||
ip, ok := isMulticastAvailable(&ifi)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
@@ -217,7 +217,7 @@ func TestIPPerInterfaceSingleConnWithSingleGroupListener(t *testing.T) {
|
||||
t.Fatalf("net.Interfaces failed: %v", err)
|
||||
}
|
||||
for i, ifi := range ift {
|
||||
ip, ok := isGoodForMulticast(&ifi)
|
||||
ip, ok := isMulticastAvailable(&ifi)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -33,11 +33,11 @@ func (c *payloadHandler) ReadFrom(b []byte) (n int, cm *ControlMessage, src net.
|
||||
return 0, nil, nil, err
|
||||
}
|
||||
case *net.IPConn:
|
||||
nb := make([]byte, len(b)+maxHeaderLen)
|
||||
nb := make([]byte, maxHeaderLen+len(b))
|
||||
if n, oobn, _, src, err = rd.ReadMsgIP(nb, oob); err != nil {
|
||||
return 0, nil, nil, err
|
||||
}
|
||||
hdrlen := (int(b[0]) & 0x0f) << 2
|
||||
hdrlen := int(nb[0]&0x0f) << 2
|
||||
copy(b, nb[hdrlen:])
|
||||
n -= hdrlen
|
||||
default:
|
||||
|
||||
@@ -24,9 +24,14 @@ func TestReadWriteUnicastIPPayloadUDP(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("net.ResolveUDPAddr failed: %v", err)
|
||||
}
|
||||
|
||||
p := ipv4.NewPacketConn(c)
|
||||
runPayloadTransponder(t, p, []byte("HELLO-R-U-THERE"), dst)
|
||||
cf := ipv4.FlagTTL | ipv4.FlagDst | ipv4.FlagInterface
|
||||
for i, toggle := range []bool{true, false, true} {
|
||||
if err := p.SetControlMessage(cf, toggle); err != nil {
|
||||
t.Fatalf("ipv4.PacketConn.SetControlMessage failed: %v", err)
|
||||
}
|
||||
writeThenReadPayload(t, i, p, []byte("HELLO-R-U-THERE"), dst)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadWriteUnicastIPPayloadICMP(t *testing.T) {
|
||||
@@ -45,11 +50,31 @@ func TestReadWriteUnicastIPPayloadICMP(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("ResolveIPAddr failed: %v", err)
|
||||
}
|
||||
|
||||
p := ipv4.NewPacketConn(c)
|
||||
id := os.Getpid() & 0xffff
|
||||
pld := newICMPEchoRequest(id, 1, 128, []byte("HELLO-R-U-THERE"))
|
||||
runPayloadTransponder(t, p, pld, dst)
|
||||
cf := ipv4.FlagTTL | ipv4.FlagDst | ipv4.FlagInterface
|
||||
for i, toggle := range []bool{true, false, true} {
|
||||
wb, err := (&icmpMessage{
|
||||
Type: icmpv4EchoRequest, Code: 0,
|
||||
Body: &icmpEcho{
|
||||
ID: os.Getpid() & 0xffff, Seq: i + 1,
|
||||
Data: []byte("HELLO-R-U-THERE"),
|
||||
},
|
||||
}).Marshal()
|
||||
if err != nil {
|
||||
t.Fatalf("icmpMessage.Marshal failed: %v", err)
|
||||
}
|
||||
if err := p.SetControlMessage(cf, toggle); err != nil {
|
||||
t.Fatalf("ipv4.PacketConn.SetControlMessage failed: %v", err)
|
||||
}
|
||||
rb := writeThenReadPayload(t, i, p, wb, dst)
|
||||
m, err := parseICMPMessage(rb)
|
||||
if err != nil {
|
||||
t.Fatalf("parseICMPMessage failed: %v", err)
|
||||
}
|
||||
if m.Type != icmpv4EchoReply || m.Code != 0 {
|
||||
t.Fatalf("got type=%v, code=%v; expected type=%v, code=%v", m.Type, m.Code, icmpv4EchoReply, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadWriteUnicastIPDatagram(t *testing.T) {
|
||||
@@ -68,12 +93,32 @@ func TestReadWriteUnicastIPDatagram(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("ResolveIPAddr failed: %v", err)
|
||||
}
|
||||
|
||||
r, err := ipv4.NewRawConn(c)
|
||||
if err != nil {
|
||||
t.Fatalf("ipv4.NewRawConn failed: %v", err)
|
||||
}
|
||||
id := os.Getpid() & 0xffff
|
||||
pld := newICMPEchoRequest(id, 1, 128, []byte("HELLO-R-U-THERE"))
|
||||
runDatagramTransponder(t, r, pld, nil, dst)
|
||||
cf := ipv4.FlagTTL | ipv4.FlagDst | ipv4.FlagInterface
|
||||
for i, toggle := range []bool{true, false, true} {
|
||||
wb, err := (&icmpMessage{
|
||||
Type: icmpv4EchoRequest, Code: 0,
|
||||
Body: &icmpEcho{
|
||||
ID: os.Getpid() & 0xffff, Seq: i + 1,
|
||||
Data: []byte("HELLO-R-U-THERE"),
|
||||
},
|
||||
}).Marshal()
|
||||
if err != nil {
|
||||
t.Fatalf("icmpMessage.Marshal failed: %v", err)
|
||||
}
|
||||
if err := r.SetControlMessage(cf, toggle); err != nil {
|
||||
t.Fatalf("ipv4.RawConn.SetControlMessage failed: %v", err)
|
||||
}
|
||||
rb := writeThenReadDatagram(t, i, r, wb, nil, dst)
|
||||
m, err := parseICMPMessage(rb)
|
||||
if err != nil {
|
||||
t.Fatalf("parseICMPMessage failed: %v", err)
|
||||
}
|
||||
if m.Type != icmpv4EchoReply || m.Code != 0 {
|
||||
t.Fatalf("got type=%v, code=%v; expected type=%v, code=%v", m.Type, m.Code, icmpv4EchoReply, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user