// NlConnect is same with libnl nl_connect. nl_close is required for releaseing internal fd. func NlConnect(sk *NlSock, protocol int) error { if sk.Fd != -1 { return NLE_BAD_SOCK } if fd, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW|syscall.SOCK_CLOEXEC, protocol); err != nil { return err } else { sk.Fd = fd } if sk.Flags&NL_SOCK_BUFSIZE_SET != 0 { if err := NlSocketSetBufferSize(sk, 0, 0); err != nil { return err } } if sk.Local.Pid == 0 { // _nl_socket_is_local_port_unspecified pid := syscall.Getpid() var local *syscall.SockaddrNetlink for high := 1023; high > 0; high-- { if next := func() bool { pidLock.Lock() defer pidLock.Unlock() if _, exists := pidUsed[high]; !exists { pidUsed[high] = true return false } return true }(); next { continue } local = &syscall.SockaddrNetlink{ Pid: uint32((high << 22) | (pid & 0x3FFFFF)), } if err := syscall.Bind(sk.Fd, local); err == nil { break } else if err != syscall.EADDRINUSE { return err } else { local = nil } } if local == nil { return NLE_EXIST } sk.Local = *local sk.Flags &^= NL_OWN_PORT } else { if err := syscall.Bind(sk.Fd, &(sk.Local)); err != nil { return err } } return nil }
// Create a tcp socket, setting the TCP_FASTOPEN socket option. func (s *TFOServer) Bind() (err error) { s.fd, err = syscall.Socket(syscall.AF_INET, syscall.SOCK_STREAM, 0) if err != nil { if err == syscall.ENOPROTOOPT { err = errors.New("TCP Fast Open server support is unavailable (unsupported kernel).") } return } err = syscall.SetsockoptInt(s.fd, syscall.SOL_TCP, TCP_FASTOPEN, 1) if err != nil { err = errors.New(fmt.Sprintf("Failed to set necessary TCP_FASTOPEN socket option: %s", err)) return } sa := &syscall.SockaddrInet4{Addr: s.ServerAddr, Port: s.ServerPort} err = syscall.Bind(s.fd, sa) if err != nil { err = errors.New(fmt.Sprintf("Failed to bind to Addr: %v, Port: %d, Reason: %s", s.ServerAddr, s.ServerPort, err)) return } log.Printf("Server: Bound to addr: %v, port: %d\n", s.ServerAddr, s.ServerPort) err = syscall.Listen(s.fd, LISTEN_BACKLOG) if err != nil { err = errors.New(fmt.Sprintf("Failed to listen: %s", err)) return } return }
func main() { fd, err := syscall.Socket( syscall.AF_NETLINK, syscall.SOCK_RAW, NETLINK_KOBJECT_UEVENT, ) if err != nil { log.Println(err) return } nl := syscall.SockaddrNetlink{ Family: syscall.AF_NETLINK, Pid: uint32(os.Getpid()), Groups: 1, } err = syscall.Bind(fd, &nl) if err != nil { log.Println(err) return } b := make([]byte, UEVENT_BUFFER_SIZE*2) for { n, err2 := syscall.Read(fd, b) log.Println(n, err2) log.Println(b) act, dev, subsys := parseUBuffer(b) log.Println(act, dev, subsys) } }
func advert(_ net.PacketConn, src, dst net.IP, p *net.IPNet) error { s, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP) if err != nil { return err } syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1) syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEPORT, 1) syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1) pdst := dst if *useLimited && runtime.GOOS == "freebsd" { dst = directed(p) syscall.SetsockoptInt(s, syscall.IPPROTO_IP, 0x17, 1) // IP_ONESBCAST } sa := &syscall.SockaddrInet4{Port: *port} copy(sa.Addr[:], src.To4()) if err := syscall.Bind(s, sa); err != nil { syscall.Close(s) return err } f := os.NewFile(uintptr(s), fmt.Sprintf("udp:%v->", src)) c, err := net.FilePacketConn(f) f.Close() if err != nil { return err } defer c.Close() // If you are lucky, you can see that on some platform the // kernel sometimes transmits a wrong frame addressed to IPv4 // limited broadcast address with some nexthop's link-layer // address on a broadcast-capable link. // In general, using BPF for transmitting IPv4 limited // broadcast addresses is a reasonable choice. _, err = c.WriteTo([]byte(fmt.Sprintf("%s-%v", runtime.GOOS, pdst)), &net.UDPAddr{IP: dst, Port: *port}) return err }
func mcastOpen(bindAddr net.IP, port int, ifname string) (*ipv4.PacketConn, *net.UDPConn, error) { s, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP) if err != nil { log.Fatal(err) } if err := syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1); err != nil { log.Fatal(err) } //syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEPORT, 1) if err := syscall.SetsockoptString(s, syscall.SOL_SOCKET, syscall.SO_BINDTODEVICE, ifname); err != nil { log.Fatal(err) } lsa := syscall.SockaddrInet4{Port: port} copy(lsa.Addr[:], bindAddr.To4()) if err := syscall.Bind(s, &lsa); err != nil { syscall.Close(s) log.Fatal(err) } f := os.NewFile(uintptr(s), "") c, err := net.FilePacketConn(f) f.Close() if err != nil { log.Fatal(err) } u := c.(*net.UDPConn) p := ipv4.NewPacketConn(c) return p, u, nil }
func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) { var probes = []struct { laddr net.TCPAddr value int ok bool }{ // IPv6 communication capability {laddr: net.TCPAddr{IP: net.ParseIP("::1")}, value: 1}, // IPv6 IPv4-mapped address communication capability {laddr: net.TCPAddr{IP: net.IPv4(127, 0, 0, 1)}, value: 0}, } for i := range probes { s, err := syscall.Socket(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_TCP) if err != nil { continue } defer closesocket(s) syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, probes[i].value) sa, err := sockaddrTCP(&probes[i].laddr, syscall.AF_INET6) if err != nil { continue } if err := syscall.Bind(s, sa); err != nil { continue } probes[i].ok = true } return probes[0].ok, probes[1].ok }
func (nlSock *NLSocket) Init() error { //16 - NETLINK_GENERIC sd, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_DGRAM, NETLINK_GENERIC) if err != nil { return fmt.Errorf("cant create netlink socket %v\n", err) } pid := uint32(syscall.Getpid()) sa := &syscall.SockaddrNetlink{ Pid: pid, Groups: 0, Family: syscall.AF_NETLINK} if err = syscall.Bind(sd, sa); err != nil { return fmt.Errorf("cant bind to netlink socket: %v\n", err) } nlSock.Lock = new(sync.Mutex) nlSock.Sd = sd nlSock.Seq = 0 nlSock.PortID = pid for k, v := range LookupOnStartup { familyId, err := nlSock.ResolveFamily(NulStringType(k)) if err != nil { return err } CreateMsgType(v, uint16(*familyId)) MT2Family[k] = uint16(*familyId) } return nil }
func main() { acceptingFd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_STREAM, 0) check(err) addr := &syscall.SockaddrInet4{Port: 3000, Addr: [4]byte{0, 0, 0, 0}} err = syscall.Bind(acceptingFd, addr) check(err) err = syscall.Listen(acceptingFd, 100) check(err) for { connectionFd, _, err := syscall.Accept(acceptingFd) check(err) fmt.Println("Accepted new connectrion") data := make([]byte, 1024) _, err = syscall.Read(connectionFd, data) check(err) fmt.Printf("Received: %s\n", string(data)) _, err = syscall.Write(connectionFd, data) check(err) err = syscall.Close(connectionFd) check(err) } }
// NewReusablePortPacketConn returns net.FileListener that created from a file discriptor for a socket with SO_REUSEPORT option. func NewReusablePortPacketConn(proto, addr string) (l net.PacketConn, err error) { var ( soType, fd int file *os.File sockaddr syscall.Sockaddr ) if sockaddr, soType, err = getSockaddr(proto, addr); err != nil { return nil, err } if fd, err = syscall.Socket(soType, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP); err != nil { return nil, err } if err = syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, reusePort, 1); err != nil { return nil, err } if err = syscall.Bind(fd, sockaddr); err != nil { return nil, err } // File Name get be nil file = os.NewFile(uintptr(fd), filePrefix+strconv.Itoa(os.Getpid())) if l, err = net.FilePacketConn(file); err != nil { return nil, err } if err = file.Close(); err != nil { return nil, err } return l, err }
func (fd *netFD) dial(laddr, raddr sockaddr, deadline time.Time, toAddr func(syscall.Sockaddr) Addr) error { var err error var lsa syscall.Sockaddr if laddr != nil { if lsa, err = laddr.sockaddr(fd.family); err != nil { return err } else if lsa != nil { if err := syscall.Bind(fd.sysfd, lsa); err != nil { return os.NewSyscallError("bind", err) } } } var rsa syscall.Sockaddr if raddr != nil { if rsa, err = raddr.sockaddr(fd.family); err != nil { return err } if err := fd.connect(lsa, rsa, deadline); err != nil { return err } fd.isConnected = true } else { if err := fd.init(); err != nil { return err } } lsa, _ = syscall.Getsockname(fd.sysfd) if rsa, _ = syscall.Getpeername(fd.sysfd); rsa != nil { fd.setAddr(toAddr(lsa), toAddr(rsa)) } else { fd.setAddr(toAddr(lsa), raddr) } return nil }
func (fd *netFD) dial(ctx context.Context, laddr, raddr sockaddr) error { var err error var lsa syscall.Sockaddr if laddr != nil { if lsa, err = laddr.sockaddr(fd.family); err != nil { return err } else if lsa != nil { if err := syscall.Bind(fd.sysfd, lsa); err != nil { return os.NewSyscallError("bind", err) } } } var rsa syscall.Sockaddr if raddr != nil { if rsa, err = raddr.sockaddr(fd.family); err != nil { return err } if err := fd.connect(ctx, lsa, rsa); err != nil { return err } fd.isConnected = true } else { if err := fd.init(); err != nil { return err } } lsa, _ = syscall.Getsockname(fd.sysfd) if rsa, _ = syscall.Getpeername(fd.sysfd); rsa != nil { fd.setAddr(fd.addrFunc()(lsa), fd.addrFunc()(rsa)) } else { fd.setAddr(fd.addrFunc()(lsa), raddr) } return nil }
// Bind our netlink socket and // send a listen control message to the connector driver. func (listener *netlinkListener) bind() error { sock, err := syscall.Socket( syscall.AF_NETLINK, syscall.SOCK_DGRAM, syscall.NETLINK_CONNECTOR) if err != nil { return err } listener.sock = sock listener.addr = &syscall.SockaddrNetlink{ Family: syscall.AF_NETLINK, Groups: _CN_IDX_PROC, Pid: uint32(os.Getpid()), } err = syscall.Bind(listener.sock, listener.addr) if err != nil { return err } return listener.send(_PROC_CN_MCAST_LISTEN) }
func (fd *netFD) connect(la, ra syscall.Sockaddr) error { // Do not need to call fd.writeLock here, // because fd is not yet accessible to user, // so no concurrent operations are possible. if !canUseConnectEx(fd.net) { return syscall.Connect(fd.sysfd, ra) } // ConnectEx windows API requires an unconnected, previously bound socket. if la == nil { switch ra.(type) { case *syscall.SockaddrInet4: la = &syscall.SockaddrInet4{} case *syscall.SockaddrInet6: la = &syscall.SockaddrInet6{} default: panic("unexpected type in connect") } if err := syscall.Bind(fd.sysfd, la); err != nil { return err } } // Call ConnectEx API. o := &fd.wop o.sa = ra _, err := wsrv.ExecIO(o, "ConnectEx", func(o *operation) error { return syscall.ConnectEx(o.fd.sysfd, o.sa, nil, 0, nil, &o.o) }) if err != nil { return err } // Refresh socket properties. return syscall.Setsockopt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_UPDATE_CONNECT_CONTEXT, (*byte)(unsafe.Pointer(&fd.sysfd)), int32(unsafe.Sizeof(fd.sysfd))) }
func (io *NetIOManager) ProxyNetListen(sa syscall.Sockaddr) error { serverfd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_TCP) if err != nil { goto Error } err = syscall.Bind(serverfd, sa) if err != nil { goto Cleanup } err = syscall.Listen(serverfd, io.max_backlog) if err != nil { goto Cleanup } err = syscall.EpollCtl(io.epoll_fd, syscall.EPOLL_CTL_ADD, serverfd, &syscall.EpollEvent{Events: syscall.EPOLLIN, Fd: int32(serverfd)}) if err != nil { goto Cleanup } io.proxy_server_fd = serverfd return nil Cleanup: syscall.Close(serverfd) Error: return err }
func (fd *netFD) connect(ra syscall.Sockaddr) error { if !canUseConnectEx(fd.net) { return syscall.Connect(fd.sysfd, ra) } // ConnectEx windows API requires an unconnected, previously bound socket. var la syscall.Sockaddr switch ra.(type) { case *syscall.SockaddrInet4: la = &syscall.SockaddrInet4{} case *syscall.SockaddrInet6: la = &syscall.SockaddrInet6{} default: panic("unexpected type in connect") } if err := syscall.Bind(fd.sysfd, la); err != nil { return err } // Call ConnectEx API. var o connectOp o.Init(fd, 'w') o.ra = ra _, err := iosrv.ExecIO(&o, fd.wdeadline.value()) if err != nil { return err } // Refresh socket properties. return syscall.Setsockopt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_UPDATE_CONNECT_CONTEXT, (*byte)(unsafe.Pointer(&fd.sysfd)), int32(unsafe.Sizeof(fd.sysfd))) }
// Should we try to use the IPv4 socket interface if we're // only dealing with IPv4 sockets? As long as the host system // understands IPv6, it's okay to pass IPv4 addresses to the IPv6 // interface. That simplifies our code and is most general. // Unfortunately, we need to run on kernels built without IPv6 // support too. So probe the kernel to figure it out. // // probeIPv6Stack probes both basic IPv6 capability and IPv6 IPv4- // mapping capability which is controlled by IPV6_V6ONLY socket // option and/or kernel state "net.inet6.ip6.v6only". // It returns two boolean values. If the first boolean value is // true, kernel supports basic IPv6 functionality. If the second // boolean value is true, kernel supports IPv6 IPv4-mapping. func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) { var probes = []struct { la TCPAddr ok bool }{ // IPv6 communication capability {TCPAddr{IP: ParseIP("::1")}, false}, // IPv6 IPv4-mapped address communication capability {TCPAddr{IP: IPv4(127, 0, 0, 1)}, false}, } for i := range probes { s, err := syscall.Socket(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_TCP) if err != nil { continue } defer closesocket(s) syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0) sa, err := probes[i].la.toAddr().sockaddr(syscall.AF_INET6) if err != nil { continue } err = syscall.Bind(s, sa) if err != nil { continue } probes[i].ok = true } return probes[0].ok, probes[1].ok }
// Generic socket creation. func socket(net string, f, t, p int, ipv6only bool, ulsa, ursa syscall.Sockaddr, deadline time.Time, toAddr func(syscall.Sockaddr) Addr) (fd *netFD, err error) { // See ../syscall/exec_unix.go for description of ForkLock. syscall.ForkLock.RLock() s, err := syscall.Socket(f, t, p) if err != nil { syscall.ForkLock.RUnlock() return nil, err } syscall.CloseOnExec(s) syscall.ForkLock.RUnlock() if err = setDefaultSockopts(s, f, t, ipv6only); err != nil { closesocket(s) return nil, err } if ulsa != nil { // We provide a socket that listens to a wildcard // address with reusable UDP port when the given ulsa // is an appropriate UDP multicast address prefix. // This makes it possible for a single UDP listener // to join multiple different group addresses, for // multiple UDP listeners that listen on the same UDP // port to join the same group address. if ulsa, err = listenerSockaddr(s, f, ulsa, toAddr); err != nil { closesocket(s) return nil, err } if err = syscall.Bind(s, ulsa); err != nil { closesocket(s) return nil, err } } if fd, err = newFD(s, f, t, net); err != nil { closesocket(s) return nil, err } if ursa != nil { if !deadline.IsZero() { fd.wdeadline = deadline.UnixNano() } if err = fd.connect(ursa); err != nil { closesocket(s) fd.Close() return nil, err } fd.isConnected = true fd.wdeadline = 0 } lsa, _ := syscall.Getsockname(s) laddr := toAddr(lsa) rsa, _ := syscall.Getpeername(s) raddr := toAddr(rsa) fd.setAddr(laddr, raddr) return fd, nil }
func CreateTCPSocket(proto, addr string) (net.Listener, error) { var err error var laddr *net.TCPAddr laddr, err = net.ResolveTCPAddr(proto, addr) if err != nil { return nil, err } family, ipv6only := favoriteTCPAddrFamily(proto, laddr, "listen") var socketAddr syscall.Sockaddr if socketAddr, err = ipToSockaddr(family, laddr.IP, laddr.Port, laddr.Zone); err != nil { panic(err) return nil, err } var s int if s, err = sysSocket(family, syscall.SOCK_STREAM, 0); err != nil { return nil, err } if err = setDefaultSockopts(s, family, syscall.SOCK_STREAM, ipv6only); err != nil { closesocket(s) return nil, err } if err = setDefaultListenerSockopts(s); err != nil { closesocket(s) return nil, err } if err = syscall.SetsockoptInt(s, syscall.SOL_SOCKET, SO_REUSEPORT, 1); err != nil { closesocket(s) panic(err) return nil, err } if err = syscall.Bind(s, socketAddr); err != nil { closesocket(s) return nil, err } if err = syscall.Listen(s, maxListenerBacklog()); err != nil { closesocket(s) return nil, err } file := os.NewFile(uintptr(s), "listener-"+laddr.String()) defer file.Close() var socketListener net.Listener if socketListener, err = net.FileListener(file); err != nil { return nil, err } return socketListener, nil }
// Bind the netlink socket to receive multicast messages func (self *Socket) Bind(pid, groups uint32) (err os.Error) { addr := &syscall.SockaddrNetlink{Pid: pid, Groups: groups} e := syscall.Bind(self.fd, addr) if e != 0 { err = os.Errno(e) } return }
// Generic socket creation. func socket(net string, f, t, p int, ipv6only bool, la, ra syscall.Sockaddr, toAddr func(syscall.Sockaddr) Addr) (fd *netFD, err error) { // See ../syscall/exec.go for description of ForkLock. syscall.ForkLock.RLock() s, err := syscall.Socket(f, t, p) if err != nil { syscall.ForkLock.RUnlock() return nil, err } syscall.CloseOnExec(s) syscall.ForkLock.RUnlock() err = setDefaultSockopts(s, f, t, ipv6only) if err != nil { closesocket(s) return nil, err } var bla syscall.Sockaddr if la != nil { bla, err = listenerSockaddr(s, f, la, toAddr) if err != nil { closesocket(s) return nil, err } err = syscall.Bind(s, bla) if err != nil { closesocket(s) return nil, err } } if fd, err = newFD(s, f, t, net); err != nil { closesocket(s) return nil, err } if ra != nil { if err = fd.connect(ra); err != nil { closesocket(s) fd.Close() return nil, err } fd.isConnected = true } sa, _ := syscall.Getsockname(s) var laddr Addr if la != nil && bla != la { laddr = toAddr(la) } else { laddr = toAddr(sa) } sa, _ = syscall.Getpeername(s) raddr := toAddr(sa) fd.setAddr(laddr, raddr) return fd, nil }
func traceOne(addr *syscall.SockaddrInet4, ttl int) *ReturnArgs { cli, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP) if err != nil { exitWithError(err) } srv, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, syscall.IPPROTO_ICMP) if err != nil { exitWithError(err) } defer syscall.Close(cli) defer syscall.Close(srv) // set ttl, stolen from somewhere else... // https://github.com/aeden/traceroute/blob/master/traceroute.go#L195 if err := syscall.SetsockoptInt(cli, syscall.SOL_IP, syscall.IP_TTL, ttl); err != nil { exitWithError(err) } // set timeout, stolen from somewhere else... // https://github.com/aeden/traceroute/blob/master/traceroute.go#L197 tv := syscall.NsecToTimeval(1e6 * TIMEOUT) if err := syscall.SetsockoptTimeval(srv, syscall.SOL_SOCKET, syscall.SO_RCVTIMEO, &tv); err != nil { exitWithError(err) } if err := syscall.Bind(srv, toAddr(HOST, RECV_PORT)); err != nil { exitWithError(err) } rr := &ReturnArgs{} start := time.Now() if err := syscall.Sendto(cli, makeICMP(), 0, addr); err != nil { return rr } buf := make([]byte, 512) _, from, err := syscall.Recvfrom(srv, buf, 0) if err != nil { return rr } rr.elapsed = float64(time.Since(start).Nanoseconds()) / 1e6 t, c := parseICMP(buf) if t == 3 && c == 3 { // Destination port unreachable, type==3 && code==3 rr.done = true } else if t != 11 { // Time Exceeded, type==11 && code in (0,1) return rr } rr.ok = true rr.ip = toStr(from) addrs, err := net.LookupAddr(rr.ip) if err != nil { rr.addr = rr.ip } else { rr.addr = addrs[0] } return rr }
// Generic POSIX socket creation. func socket(net string, f, t, p int, ipv6only bool, ulsa, ursa syscall.Sockaddr, deadline time.Time, toAddr func(syscall.Sockaddr) Addr) (fd *netFD, err error) { s, err := sysSocket(f, t, p) if err != nil { return nil, err } if err = setDefaultSockopts(s, f, t, ipv6only); err != nil { closesocket(s) return nil, err } if ulsa != nil { // We provide a socket that listens to a wildcard // address with reusable UDP port when the given ulsa // is an appropriate UDP multicast address prefix. // This makes it possible for a single UDP listener // to join multiple different group addresses, for // multiple UDP listeners that listen on the same UDP // port to join the same group address. if ulsa, err = listenerSockaddr(s, f, ulsa, toAddr); err != nil { closesocket(s) return nil, err } if err = syscall.Bind(s, ulsa); err != nil { closesocket(s) return nil, err } } if fd, err = newFD(s, f, t, net); err != nil { closesocket(s) return nil, err } if ursa != nil { if !deadline.IsZero() { setWriteDeadline(fd, deadline) } if err = fd.connect(ursa); err != nil { closesocket(s) return nil, err } fd.isConnected = true if !deadline.IsZero() { setWriteDeadline(fd, time.Time{}) } } lsa, _ := syscall.Getsockname(s) laddr := toAddr(lsa) rsa, _ := syscall.Getpeername(s) raddr := toAddr(rsa) fd.setAddr(laddr, raddr) if fd.raddr == nil { fd.raddr = toAddr(ursa) } return fd, nil }
func receiveICMP(result chan icmpEvent) { // Set up the socket to receive inbound packets sock, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, syscall.IPPROTO_ICMP) if err != nil { result <- makeICMPErrorEvent(&icmpEvent{}, fmt.Errorf("%v. Did you forget to run as root?", err)) return } err = syscall.Bind(sock, &syscall.SockaddrInet4{}) if err != nil { result <- makeICMPErrorEvent(&icmpEvent{}, err) return } var pkt = make([]byte, 1024) for { event := icmpEvent{} _, from, err := syscall.Recvfrom(sock, pkt, 0) if err != nil { result <- makeICMPErrorEvent(&event, err) return } reader := bytes.NewReader(pkt) var ip IPHeader var icmp ICMPHeader var tcp TCPHeader err = binary.Read(reader, binary.BigEndian, &ip) if ip.Protocol != syscall.IPPROTO_ICMP { break } ipheaderlen := (ip.VerHdrLen & 0xf) * 4 reader = bytes.NewReader(pkt[ipheaderlen:]) err = binary.Read(reader, binary.BigEndian, &icmp) if icmp.Type != 11 || icmp.Code != 0 { break } err = binary.Read(reader, binary.BigEndian, &ip) if ip.Protocol != syscall.IPPROTO_TCP { break } err = binary.Read(reader, binary.BigEndian, &tcp) event.localAddr.IP = append(event.localAddr.IP, ip.SourceIP[:]...) event.localPort = int(tcp.SrcPort) // fill in the remote endpoint deatils on the event struct event.remoteAddr, _, _ = ToIPAddrAndPort(from) result <- makeICMPEvent(&event, icmpTTLExpired) } }
// Traceroute executes traceroute to given destination, using options from TracerouteOptions // and sending updates to chan c // // Outbound packets are UDP packets and inbound packets are ICMP. // // Returns an error or nil if no error occurred func Traceroute(dest *net.IPAddr, options *TracerouteOptions, c chan TraceUpdate) (err error) { var destAddr [4]byte copy(destAddr[:], dest.IP.To4()) socketAddr, err := getSocketAddr() if err != nil { return } timeoutMs := (int64)(options.TimeoutMs) tv := syscall.NsecToTimeval(1000 * 1000 * timeoutMs) ttl := 1 for { // Set up receiving socket recvSocket, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, syscall.IPPROTO_ICMP) if err != nil { log.Fatal("Cannot setup receive socket, please run as root or with CAP_NET_RAW permissions") return err } // Set up sending socket sendSocket, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP) if err != nil { log.Fatal("Cannot setup sending socket") return err } start := time.Now() syscall.SetsockoptInt(sendSocket, 0x0, syscall.IP_TTL, ttl) syscall.SetsockoptTimeval(recvSocket, syscall.SOL_SOCKET, syscall.SO_RCVTIMEO, &tv) syscall.Bind(recvSocket, &syscall.SockaddrInet4{Port: options.Port, Addr: socketAddr}) syscall.Sendto(sendSocket, []byte{0x0}, 0, &syscall.SockaddrInet4{Port: options.Port, Addr: destAddr}) var p = make([]byte, options.PacketSize) n, from, err := syscall.Recvfrom(recvSocket, p, 0) elapsed := time.Since(start) if err == nil { currAddr := from.(*syscall.SockaddrInet4).Addr hop := TraceUpdate{Success: true, Address: currAddr, N: n, ElapsedTime: elapsed, TTL: ttl} currHost, err := net.LookupAddr(hop.addressString()) if err == nil { hop.Host = currHost[0] } // Send update c <- hop ttl += 1 // We reached the destination if ttl > options.MaxTTL || currAddr == destAddr { ttl = 1 } } else { c <- TraceUpdate{Success: false, TTL: ttl} ttl += 1 } syscall.Close(recvSocket) syscall.Close(sendSocket) } }
// ListenPacket listens for incoming ICMP packets addressed to // address. See net.Dial for the syntax of address. // // For non-privileged datagram-oriented ICMP endpoints, network must // be "udp4" or "udp6". The endpoint allows to read, write a few // limited ICMP messages such as echo request and echo reply. // Currently only Darwin and Linux support this. // // Examples: // ListenPacket("udp4", "192.168.0.1") // ListenPacket("udp4", "0.0.0.0") // ListenPacket("udp6", "fe80::1%en0") // ListenPacket("udp6", "::") // // For privileged raw ICMP endpoints, network must be "ip4" or "ip6" // followed by a colon and an ICMP protocol number or name. // // Examples: // ListenPacket("ip4:icmp", "192.168.0.1") // ListenPacket("ip4:1", "0.0.0.0") // ListenPacket("ip6:ipv6-icmp", "fe80::1%en0") // ListenPacket("ip6:58", "::") func ListenPacket(network, address string) (*PacketConn, error) { var family, proto int switch network { case "udp4": family, proto = syscall.AF_INET, iana.ProtocolICMP case "udp6": family, proto = syscall.AF_INET6, iana.ProtocolIPv6ICMP default: i := last(network, ':') switch network[:i] { case "ip4": proto = iana.ProtocolICMP case "ip6": proto = iana.ProtocolIPv6ICMP } } var cerr error var c net.PacketConn switch family { case syscall.AF_INET, syscall.AF_INET6: s, err := syscall.Socket(family, syscall.SOCK_DGRAM, proto) if err != nil { return nil, os.NewSyscallError("socket", err) } if runtime.GOOS == "darwin" && family == syscall.AF_INET { if err := syscall.SetsockoptInt(s, iana.ProtocolIP, sysIP_STRIPHDR, 1); err != nil { syscall.Close(s) return nil, os.NewSyscallError("setsockopt", err) } } sa, err := sockaddr(family, address) if err != nil { syscall.Close(s) return nil, err } if err := syscall.Bind(s, sa); err != nil { syscall.Close(s) return nil, os.NewSyscallError("bind", err) } f := os.NewFile(uintptr(s), "datagram-oriented icmp") c, cerr = net.FilePacketConn(f) f.Close() default: c, cerr = net.ListenPacket(network, address) } if cerr != nil { return nil, cerr } switch proto { case iana.ProtocolICMP: return &PacketConn{c: c, p4: ipv4.NewPacketConn(c)}, nil case iana.ProtocolIPv6ICMP: return &PacketConn{c: c, p6: ipv6.NewPacketConn(c)}, nil default: return &PacketConn{c: c}, nil } }
func TestSocketPacketConn(t *testing.T) { s, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW, syscall.NETLINK_ROUTE) if err != nil { t.Fatal(err) } lsa := syscall.SockaddrNetlink{Family: syscall.AF_NETLINK} if err := syscall.Bind(s, &lsa); err != nil { syscall.Close(s) t.Fatal(err) } f := os.NewFile(uintptr(s), "netlink") c, err := SocketPacketConn(f, &netlinkAddr{}) f.Close() if err != nil { t.Fatal(err) } defer c.Close() const N = 3 var wg sync.WaitGroup wg.Add(2 * N) dst := &netlinkAddr{PID: 0} for i := 0; i < N; i++ { go func() { defer wg.Done() l := syscall.NLMSG_HDRLEN + syscall.SizeofRtGenmsg b := make([]byte, l) *(*uint32)(unsafe.Pointer(&b[0:4][0])) = uint32(l) *(*uint16)(unsafe.Pointer(&b[4:6][0])) = uint16(syscall.RTM_GETLINK) *(*uint16)(unsafe.Pointer(&b[6:8][0])) = uint16(syscall.NLM_F_DUMP | syscall.NLM_F_REQUEST) *(*uint32)(unsafe.Pointer(&b[8:12][0])) = uint32(1) *(*uint32)(unsafe.Pointer(&b[12:16][0])) = uint32(0) b[16] = byte(syscall.AF_UNSPEC) if _, err := c.WriteTo(b, dst); err != nil { t.Error(err) return } }() } for i := 0; i < N; i++ { go func() { defer wg.Done() b := make([]byte, os.Getpagesize()) n, _, err := c.ReadFrom(b) if err != nil { t.Error(err) return } if _, err := syscall.ParseNetlinkMessage(b[:n]); err != nil { t.Error(err) return } }() } wg.Wait() }
// Generic socket creation. func socket(net string, f, p, t int, la, ra syscall.Sockaddr, toAddr func(syscall.Sockaddr) Addr) (fd *netFD, err os.Error) { // See ../syscall/exec.go for description of ForkLock. syscall.ForkLock.RLock() s, e := syscall.Socket(f, p, t) if e != 0 { syscall.ForkLock.RUnlock() return nil, os.Errno(e) } syscall.CloseOnExec(s) syscall.ForkLock.RUnlock() // Allow reuse of recently-used addresses. syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1) // Allow broadcast. syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1) if f == syscall.AF_INET6 { // using ip, tcp, udp, etc. // allow both protocols even if the OS default is otherwise. syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0) } if la != nil { e = syscall.Bind(s, la) if e != 0 { closesocket(s) return nil, os.Errno(e) } } if ra != nil { e = syscall.Connect(s, ra) for e == syscall.EINTR { e = syscall.Connect(s, ra) } if e != 0 { closesocket(s) return nil, os.Errno(e) } } sa, _ := syscall.Getsockname(s) laddr := toAddr(sa) sa, _ = syscall.Getpeername(s) raddr := toAddr(sa) fd, err = newFD(s, f, p, net, laddr, raddr) if err != nil { closesocket(s) return nil, err } return fd, nil }
func Hop(port, ttl int, IP_addr net.IP) (*Hop_ret, error) { ret_addr := net.IPv4(0, 0, 0, 0) success := false // make sockets send_udp_s, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP) if err != nil { return nil, err } recv_icmp_s, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, syscall.IPPROTO_ICMP) if err != nil { return nil, err } //editing TTL value for outgoing IPv4 packets if err := syscall.SetsockoptInt(send_udp_s, syscall.SOL_IP, syscall.IP_TTL, ttl); err != nil { return nil, err } tv := syscall.NsecToTimeval(1000 * 1000 * TIME_OUT_MS) syscall.SetsockoptTimeval(recv_icmp_s, syscall.SOL_SOCKET, syscall.SO_RCVTIMEO, &tv) defer syscall.Close(send_udp_s) defer syscall.Close(recv_icmp_s) //connect sockets if err := syscall.Bind(recv_icmp_s, &syscall.SockaddrInet4{Port: port, Addr: [4]byte{137, 224, 226, 47}}); err != nil { return nil, err } //send udp-packet var IP [4]byte copy(IP[:], IP_addr.To4()) if err := syscall.Sendto(send_udp_s, []byte{0x42, 0x42}, 0, &syscall.SockaddrInet4{Port: 1337, Addr: IP}); err != nil { return nil, err } //receive ICMP recv_buffer := make([]byte, 4096) _, _, err = syscall.Recvfrom(recv_icmp_s, recv_buffer, 0) if err == nil { header, err := ipv4.ParseHeader(recv_buffer) if err != nil { log.Errorf("%q", err) } success = true ret_addr = header.Src } else { //time out success = false ret_addr = net.IPv4(0, 0, 0, 0) //log.Errorf("%q", err) } //resolve (timeout) errors, retry or return false... return &Hop_ret{Addr: ret_addr, TTL: ttl, success: success}, nil }
// Listen returns TCP listener with SO_REUSEPORT option set. // // Only tcp4 network is supported. // // ErrNoReusePort error is returned if the system doesn't support SO_REUSEPORT. func Listen(network, addr string) (l net.Listener, err error) { var ( soType, fd int file *os.File sockaddr syscall.Sockaddr ) if sockaddr, soType, err = getSockaddr(network, addr); err != nil { return nil, err } syscall.ForkLock.RLock() fd, err = syscall.Socket(soType, syscall.SOCK_STREAM, syscall.IPPROTO_TCP) if err == nil { syscall.CloseOnExec(fd) } syscall.ForkLock.RUnlock() if err != nil { return nil, err } if err = syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1); err != nil { syscall.Close(fd) return nil, err } if err = syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, soReusePort, 1); err != nil { syscall.Close(fd) return nil, &ErrNoReusePort{err} } if err = syscall.Bind(fd, sockaddr); err != nil { syscall.Close(fd) return nil, err } if err = syscall.Listen(fd, syscall.SOMAXCONN); err != nil { syscall.Close(fd) return nil, err } name := fmt.Sprintf("reuseport.%d.%s.%s", os.Getpid(), network, addr) file = os.NewFile(uintptr(fd), name) if l, err = net.FileListener(file); err != nil { file.Close() return nil, err } if err = file.Close(); err != nil { l.Close() return nil, err } return l, err }
func listen2(path string) int { _, err := os.Stat(path) if err == nil { os.Remove(path) } fd, _ := syscall.Socket(syscall.AF_LOCAL, syscall.SOCK_STREAM|syscall.SOCK_CLOEXEC, 0) addr := &syscall.SockaddrUnix{Name: path} syscall.Bind(fd, addr) syscall.Listen(fd, 1) return fd }