github.com/mh-cbon/go@v0.0.0-20160603070303-9e112a3fe4c0/src/net/iprawsock_posix.go (about) 1 // Copyright 2010 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows 6 7 package net 8 9 import ( 10 "context" 11 "syscall" 12 ) 13 14 // BUG(mikio): On every POSIX platform, reads from the "ip4" network 15 // using the ReadFrom or ReadFromIP method might not return a complete 16 // IPv4 packet, including its header, even if there is space 17 // available. This can occur even in cases where Read or ReadMsgIP 18 // could return a complete packet. For this reason, it is recommended 19 // that you do not uses these methods if it is important to receive a 20 // full packet. 21 // 22 // The Go 1 compatibility guidelines make it impossible for us to 23 // change the behavior of these methods; use Read or ReadMsgIP 24 // instead. 25 26 func sockaddrToIP(sa syscall.Sockaddr) Addr { 27 switch sa := sa.(type) { 28 case *syscall.SockaddrInet4: 29 return &IPAddr{IP: sa.Addr[0:]} 30 case *syscall.SockaddrInet6: 31 return &IPAddr{IP: sa.Addr[0:], Zone: zoneToString(int(sa.ZoneId))} 32 } 33 return nil 34 } 35 36 func (a *IPAddr) family() int { 37 if a == nil || len(a.IP) <= IPv4len { 38 return syscall.AF_INET 39 } 40 if a.IP.To4() != nil { 41 return syscall.AF_INET 42 } 43 return syscall.AF_INET6 44 } 45 46 func (a *IPAddr) sockaddr(family int) (syscall.Sockaddr, error) { 47 if a == nil { 48 return nil, nil 49 } 50 return ipToSockaddr(family, a.IP, 0, a.Zone) 51 } 52 53 func (c *IPConn) readFrom(b []byte) (int, *IPAddr, error) { 54 // TODO(cw,rsc): consider using readv if we know the family 55 // type to avoid the header trim/copy 56 var addr *IPAddr 57 n, sa, err := c.fd.readFrom(b) 58 switch sa := sa.(type) { 59 case *syscall.SockaddrInet4: 60 addr = &IPAddr{IP: sa.Addr[0:]} 61 n = stripIPv4Header(n, b) 62 case *syscall.SockaddrInet6: 63 addr = &IPAddr{IP: sa.Addr[0:], Zone: zoneToString(int(sa.ZoneId))} 64 } 65 return n, addr, err 66 } 67 68 func stripIPv4Header(n int, b []byte) int { 69 if len(b) < 20 { 70 return n 71 } 72 l := int(b[0]&0x0f) << 2 73 if 20 > l || l > len(b) { 74 return n 75 } 76 if b[0]>>4 != 4 { 77 return n 78 } 79 copy(b, b[l:]) 80 return n - l 81 } 82 83 func (c *IPConn) readMsg(b, oob []byte) (n, oobn, flags int, addr *IPAddr, err error) { 84 var sa syscall.Sockaddr 85 n, oobn, flags, sa, err = c.fd.readMsg(b, oob) 86 switch sa := sa.(type) { 87 case *syscall.SockaddrInet4: 88 addr = &IPAddr{IP: sa.Addr[0:]} 89 case *syscall.SockaddrInet6: 90 addr = &IPAddr{IP: sa.Addr[0:], Zone: zoneToString(int(sa.ZoneId))} 91 } 92 return 93 } 94 95 func (c *IPConn) writeTo(b []byte, addr *IPAddr) (int, error) { 96 if c.fd.isConnected { 97 return 0, ErrWriteToConnected 98 } 99 if addr == nil { 100 return 0, errMissingAddress 101 } 102 sa, err := addr.sockaddr(c.fd.family) 103 if err != nil { 104 return 0, err 105 } 106 return c.fd.writeTo(b, sa) 107 } 108 109 func (c *IPConn) writeMsg(b, oob []byte, addr *IPAddr) (n, oobn int, err error) { 110 if c.fd.isConnected { 111 return 0, 0, ErrWriteToConnected 112 } 113 if addr == nil { 114 return 0, 0, errMissingAddress 115 } 116 sa, err := addr.sockaddr(c.fd.family) 117 if err != nil { 118 return 0, 0, err 119 } 120 return c.fd.writeMsg(b, oob, sa) 121 } 122 123 func dialIP(ctx context.Context, netProto string, laddr, raddr *IPAddr) (*IPConn, error) { 124 network, proto, err := parseNetwork(ctx, netProto) 125 if err != nil { 126 return nil, err 127 } 128 switch network { 129 case "ip", "ip4", "ip6": 130 default: 131 return nil, UnknownNetworkError(netProto) 132 } 133 if raddr == nil { 134 return nil, errMissingAddress 135 } 136 fd, err := internetSocket(ctx, network, laddr, raddr, syscall.SOCK_RAW, proto, "dial") 137 if err != nil { 138 return nil, err 139 } 140 return newIPConn(fd), nil 141 } 142 143 func listenIP(ctx context.Context, netProto string, laddr *IPAddr) (*IPConn, error) { 144 network, proto, err := parseNetwork(ctx, netProto) 145 if err != nil { 146 return nil, err 147 } 148 switch network { 149 case "ip", "ip4", "ip6": 150 default: 151 return nil, UnknownNetworkError(netProto) 152 } 153 fd, err := internetSocket(ctx, network, laddr, nil, syscall.SOCK_RAW, proto, "listen") 154 if err != nil { 155 return nil, err 156 } 157 return newIPConn(fd), nil 158 }