Source file src/net/iprawsock.go

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

View as plain text