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//go:build unix || js || wasip1 || windows 6 7package net 8 9import ( 10 "context" 11 "syscall" 12) 13 14func sockaddrToIP(sa syscall.Sockaddr) Addr { 15 switch sa := sa.(type) { 16 case *syscall.SockaddrInet4: 17 return &IPAddr{IP: sa.Addr[0:]} 18 case *syscall.SockaddrInet6: 19 return &IPAddr{IP: sa.Addr[0:], Zone: zoneCache.name(int(sa.ZoneId))} 20 } 21 return nil 22} 23 24func (a *IPAddr) family() int { 25 if a == nil || len(a.IP) <= IPv4len { 26 return syscall.AF_INET 27 } 28 if a.IP.To4() != nil { 29 return syscall.AF_INET 30 } 31 return syscall.AF_INET6 32} 33 34func (a *IPAddr) sockaddr(family int) (syscall.Sockaddr, error) { 35 if a == nil { 36 return nil, nil 37 } 38 return ipToSockaddr(family, a.IP, 0, a.Zone) 39} 40 41func (a *IPAddr) toLocal(net string) sockaddr { 42 return &IPAddr{loopbackIP(net), a.Zone} 43} 44 45func (c *IPConn) readFrom(b []byte) (int, *IPAddr, error) { 46 // TODO(cw,rsc): consider using readv if we know the family 47 // type to avoid the header trim/copy 48 var addr *IPAddr 49 n, sa, err := c.fd.readFrom(b) 50 switch sa := sa.(type) { 51 case *syscall.SockaddrInet4: 52 addr = &IPAddr{IP: sa.Addr[0:]} 53 n = stripIPv4Header(n, b) 54 case *syscall.SockaddrInet6: 55 addr = &IPAddr{IP: sa.Addr[0:], Zone: zoneCache.name(int(sa.ZoneId))} 56 } 57 return n, addr, err 58} 59 60func stripIPv4Header(n int, b []byte) int { 61 if len(b) < 20 { 62 return n 63 } 64 l := int(b[0]&0x0f) << 2 65 if 20 > l || l > len(b) { 66 return n 67 } 68 if b[0]>>4 != 4 { 69 return n 70 } 71 copy(b, b[l:]) 72 return n - l 73} 74 75func (c *IPConn) readMsg(b, oob []byte) (n, oobn, flags int, addr *IPAddr, err error) { 76 var sa syscall.Sockaddr 77 n, oobn, flags, sa, err = c.fd.readMsg(b, oob, 0) 78 switch sa := sa.(type) { 79 case *syscall.SockaddrInet4: 80 addr = &IPAddr{IP: sa.Addr[0:]} 81 case *syscall.SockaddrInet6: 82 addr = &IPAddr{IP: sa.Addr[0:], Zone: zoneCache.name(int(sa.ZoneId))} 83 } 84 return 85} 86 87func (c *IPConn) writeTo(b []byte, addr *IPAddr) (int, error) { 88 if c.fd.isConnected { 89 return 0, ErrWriteToConnected 90 } 91 if addr == nil { 92 return 0, errMissingAddress 93 } 94 sa, err := addr.sockaddr(c.fd.family) 95 if err != nil { 96 return 0, err 97 } 98 return c.fd.writeTo(b, sa) 99} 100 101func (c *IPConn) writeMsg(b, oob []byte, addr *IPAddr) (n, oobn int, err error) { 102 if c.fd.isConnected { 103 return 0, 0, ErrWriteToConnected 104 } 105 if addr == nil { 106 return 0, 0, errMissingAddress 107 } 108 sa, err := addr.sockaddr(c.fd.family) 109 if err != nil { 110 return 0, 0, err 111 } 112 return c.fd.writeMsg(b, oob, sa) 113} 114 115func (sd *sysDialer) dialIP(ctx context.Context, laddr, raddr *IPAddr) (*IPConn, error) { 116 network, proto, err := parseNetwork(ctx, sd.network, true) 117 if err != nil { 118 return nil, err 119 } 120 switch network { 121 case "ip", "ip4", "ip6": 122 default: 123 return nil, UnknownNetworkError(sd.network) 124 } 125 ctrlCtxFn := sd.Dialer.ControlContext 126 if ctrlCtxFn == nil && sd.Dialer.Control != nil { 127 ctrlCtxFn = func(ctx context.Context, network, address string, c syscall.RawConn) error { 128 return sd.Dialer.Control(network, address, c) 129 } 130 } 131 fd, err := internetSocket(ctx, network, laddr, raddr, syscall.SOCK_RAW, proto, "dial", ctrlCtxFn) 132 if err != nil { 133 return nil, err 134 } 135 return newIPConn(fd), nil 136} 137 138func (sl *sysListener) listenIP(ctx context.Context, laddr *IPAddr) (*IPConn, error) { 139 network, proto, err := parseNetwork(ctx, sl.network, true) 140 if err != nil { 141 return nil, err 142 } 143 switch network { 144 case "ip", "ip4", "ip6": 145 default: 146 return nil, UnknownNetworkError(sl.network) 147 } 148 var ctrlCtxFn func(ctx context.Context, network, address string, c syscall.RawConn) error 149 if sl.ListenConfig.Control != nil { 150 ctrlCtxFn = func(ctx context.Context, network, address string, c syscall.RawConn) error { 151 return sl.ListenConfig.Control(network, address, c) 152 } 153 } 154 fd, err := internetSocket(ctx, network, laddr, nil, syscall.SOCK_RAW, proto, "listen", ctrlCtxFn) 155 if err != nil { 156 return nil, err 157 } 158 return newIPConn(fd), nil 159} 160