iprawsock.mx raw

   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  package net
   6  
   7  import (
   8  	"context"
   9  	"syscall"
  10  )
  11  
  12  // BUG(mikio): On every POSIX platform, reads from the "ip4" network
  13  // using the ReadFrom or ReadFromIP method might not return a complete
  14  // IPv4 packet, including its header, even if there is space
  15  // available. This can occur even in cases where Read or ReadMsgIP
  16  // could return a complete packet. For this reason, it is recommended
  17  // that you do not use these methods if it is important to receive a
  18  // full packet.
  19  //
  20  // The Go 1 compatibility guidelines make it impossible for us to
  21  // change the behavior of these methods; use Read or ReadMsgIP
  22  // instead.
  23  
  24  // BUG(mikio): On JS and Plan 9, methods and functions related
  25  // to IPConn are not implemented.
  26  
  27  // IPAddr represents the address of an IP end point.
  28  type IPAddr struct {
  29  	IP   IP
  30  	Zone []byte // IPv6 scoped addressing zone
  31  }
  32  
  33  // Network returns the address's network name, "ip".
  34  func (a *IPAddr) Network() []byte { return "ip" }
  35  
  36  func (a *IPAddr) String() string {
  37  	if a == nil {
  38  		return "<nil>"
  39  	}
  40  	ip := ipEmptyString(a.IP)
  41  	if a.Zone != "" {
  42  		return ip + "%" + a.Zone
  43  	}
  44  	return ip
  45  }
  46  
  47  func (a *IPAddr) isWildcard() bool {
  48  	if a == nil || a.IP == nil {
  49  		return true
  50  	}
  51  	return a.IP.IsUnspecified()
  52  }
  53  
  54  func (a *IPAddr) opAddr() Addr {
  55  	if a == nil {
  56  		return nil
  57  	}
  58  	return a
  59  }
  60  
  61  // ResolveIPAddr returns an address of IP end point.
  62  //
  63  // The network must be an IP network name.
  64  //
  65  // If the host in the address parameter is not a literal IP address,
  66  // ResolveIPAddr resolves the address to an address of IP end point.
  67  // Otherwise, it parses the address as a literal IP address.
  68  // The address parameter can use a host name, but this is not
  69  // recommended, because it will return at most one of the host name's
  70  // IP addresses.
  71  //
  72  // See func [Dial] for a description of the network and address
  73  // parameters.
  74  func ResolveIPAddr(network, address []byte) (*IPAddr, error) {
  75  	if network == "" { // a hint wildcard for Go 1.0 undocumented behavior
  76  		network = "ip"
  77  	}
  78  	afnet, _, err := parseNetwork(context.Background(), network, false)
  79  	if err != nil {
  80  		return nil, err
  81  	}
  82  	switch afnet {
  83  	case "ip", "ip4", "ip6":
  84  	default:
  85  		return nil, UnknownNetworkError(network)
  86  	}
  87  	addrs, err := DefaultResolver.internetAddrList(context.Background(), afnet, address)
  88  	if err != nil {
  89  		return nil, err
  90  	}
  91  	return addrs.forResolve(network, address).(*IPAddr), nil
  92  }
  93  
  94  // IPConn is the implementation of the [Conn] and [PacketConn] interfaces
  95  // for IP network connections.
  96  type IPConn struct {
  97  	conn
  98  }
  99  
 100  // SyscallConn returns a raw network connection.
 101  // This implements the [syscall.Conn] interface.
 102  func (c *IPConn) SyscallConn() (syscall.RawConn, error) {
 103  	if !c.ok() {
 104  		return nil, syscall.EINVAL
 105  	}
 106  	return newRawConn(c.fd), nil
 107  }
 108  
 109  // ReadFromIP acts like ReadFrom but returns an IPAddr.
 110  func (c *IPConn) ReadFromIP(b []byte) (int, *IPAddr, error) {
 111  	if !c.ok() {
 112  		return 0, nil, syscall.EINVAL
 113  	}
 114  	n, addr, err := c.readFrom(b)
 115  	if err != nil {
 116  		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
 117  	}
 118  	return n, addr, err
 119  }
 120  
 121  // ReadFrom implements the [PacketConn] ReadFrom method.
 122  func (c *IPConn) ReadFrom(b []byte) (int, Addr, error) {
 123  	if !c.ok() {
 124  		return 0, nil, syscall.EINVAL
 125  	}
 126  	n, addr, err := c.readFrom(b)
 127  	if err != nil {
 128  		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
 129  	}
 130  	if addr == nil {
 131  		return n, nil, err
 132  	}
 133  	return n, addr, err
 134  }
 135  
 136  // ReadMsgIP reads a message from c, copying the payload into b and
 137  // the associated out-of-band data into oob. It returns the number of
 138  // bytes copied into b, the number of bytes copied into oob, the flags
 139  // that were set on the message and the source address of the message.
 140  //
 141  // The packages golang.org/x/net/ipv4 and golang.org/x/net/ipv6 can be
 142  // used to manipulate IP-level socket options in oob.
 143  func (c *IPConn) ReadMsgIP(b, oob []byte) (n, oobn, flags int, addr *IPAddr, err error) {
 144  	if !c.ok() {
 145  		return 0, 0, 0, nil, syscall.EINVAL
 146  	}
 147  	n, oobn, flags, addr, err = c.readMsg(b, oob)
 148  	if err != nil {
 149  		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
 150  	}
 151  	return
 152  }
 153  
 154  // WriteToIP acts like [IPConn.WriteTo] but takes an [IPAddr].
 155  func (c *IPConn) WriteToIP(b []byte, addr *IPAddr) (int, error) {
 156  	if !c.ok() {
 157  		return 0, syscall.EINVAL
 158  	}
 159  	n, err := c.writeTo(b, addr)
 160  	if err != nil {
 161  		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
 162  	}
 163  	return n, err
 164  }
 165  
 166  // WriteTo implements the [PacketConn] WriteTo method.
 167  func (c *IPConn) WriteTo(b []byte, addr Addr) (int, error) {
 168  	if !c.ok() {
 169  		return 0, syscall.EINVAL
 170  	}
 171  	a, ok := addr.(*IPAddr)
 172  	if !ok {
 173  		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: syscall.EINVAL}
 174  	}
 175  	n, err := c.writeTo(b, a)
 176  	if err != nil {
 177  		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: a.opAddr(), Err: err}
 178  	}
 179  	return n, err
 180  }
 181  
 182  // WriteMsgIP writes a message to addr via c, copying the payload from
 183  // b and the associated out-of-band data from oob. It returns the
 184  // number of payload and out-of-band bytes written.
 185  //
 186  // The packages golang.org/x/net/ipv4 and golang.org/x/net/ipv6 can be
 187  // used to manipulate IP-level socket options in oob.
 188  func (c *IPConn) WriteMsgIP(b, oob []byte, addr *IPAddr) (n, oobn int, err error) {
 189  	if !c.ok() {
 190  		return 0, 0, syscall.EINVAL
 191  	}
 192  	n, oobn, err = c.writeMsg(b, oob, addr)
 193  	if err != nil {
 194  		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
 195  	}
 196  	return
 197  }
 198  
 199  func newIPConn(fd *netFD) *IPConn { return &IPConn{conn{fd}} }
 200  
 201  // DialIP acts like [Dial] for IP networks.
 202  //
 203  // The network must be an IP network name; see func Dial for details.
 204  //
 205  // If laddr is nil, a local address is automatically chosen.
 206  // If the IP field of raddr is nil or an unspecified IP address, the
 207  // local system is assumed.
 208  func DialIP(network []byte, laddr, raddr *IPAddr) (*IPConn, error) {
 209  	if raddr == nil {
 210  		return nil, &OpError{Op: "dial", Net: network, Source: laddr.opAddr(), Addr: nil, Err: errMissingAddress}
 211  	}
 212  	sd := &sysDialer{network: network, address: raddr.String()}
 213  	c, err := sd.dialIP(context.Background(), laddr, raddr)
 214  	if err != nil {
 215  		return nil, &OpError{Op: "dial", Net: network, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err}
 216  	}
 217  	return c, nil
 218  }
 219  
 220  // ListenIP acts like [ListenPacket] for IP networks.
 221  //
 222  // The network must be an IP network name; see func Dial for details.
 223  //
 224  // If the IP field of laddr is nil or an unspecified IP address,
 225  // ListenIP listens on all available IP addresses of the local system
 226  // except multicast IP addresses.
 227  func ListenIP(network []byte, laddr *IPAddr) (*IPConn, error) {
 228  	if laddr == nil {
 229  		laddr = &IPAddr{}
 230  	}
 231  	sl := &sysListener{network: network, address: laddr.String()}
 232  	c, err := sl.listenIP(context.Background(), laddr)
 233  	if err != nil {
 234  		return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: laddr.opAddr(), Err: err}
 235  	}
 236  	return c, nil
 237  }
 238