func RemoteRecvCredentials(conn *net.UnixConn) (uint32, uint32, error) { err := syscall.SetsockoptInt(sysfd(conn), syscall.SOL_SOCKET, syscall.SO_PASSCRED, 1) if err != nil { return 0, 0, err } oob := make([]byte, len(syscall.UnixCredentials(&syscall.Ucred{}))) _, _, _, _, err = conn.ReadMsgUnix(nil, oob) if err != nil { return 0, 0, err } scm, err := syscall.ParseSocketControlMessage(oob) if err != nil { return 0, 0, err } ucred, err := syscall.ParseUnixCredentials(&scm[0]) if err != nil { return 0, 0, err } return ucred.Uid, ucred.Gid, nil }
func (fd *Fd) readFrom(c *net.UnixConn) error { var b []byte oob := make([]byte, 16) _, oobn, _, _, err := c.ReadMsgUnix(b, oob) if err != nil { return err } if oobn == 0 { return errors.New("error reading oob") } oob = oob[:oobn] scms, err := syscall.ParseSocketControlMessage(oob) if err != nil { return err } if len(scms) != 1 { return fmt.Errorf("expected 1 SocketControlMessage, got %d", len(scms)) } scm := scms[0] fds, err := syscall.ParseUnixRights(&scm) if err != nil { return nil } if len(fds) != 1 { return fmt.Errorf("expected 1 fd, got %d", len(fds)) } *fd = Fd(fds[0]) return nil }
func extractFds(oob []byte) (fds []int) { // Grab forklock to make sure no forks accidentally inherit the new // fds before they are made CLOEXEC // There is a slight race condition between ReadMsgUnix returns and // when we grap the lock, so this is not perfect. Unfortunately // There is no way to pass MSG_CMSG_CLOEXEC to recvmsg() nor any // way to implement non-blocking i/o in go, so this is hard to fix. syscall.ForkLock.Lock() defer syscall.ForkLock.Unlock() scms, err := syscall.ParseSocketControlMessage(oob) if err != nil { return } for _, scm := range scms { gotFds, err := syscall.ParseUnixRights(&scm) if err != nil { continue } fds = append(fds, gotFds...) for _, fd := range fds { syscall.CloseOnExec(fd) } } return }
func parseControlMessage(b []byte) (*ControlMessage, error) { cmsgs, err := syscall.ParseSocketControlMessage(b) if err != nil { return nil, os.NewSyscallError("parse socket control message", err) } if len(b) == 0 { return nil, nil } cm := &ControlMessage{} for _, m := range cmsgs { if m.Header.Level != ianaProtocolIP { continue } switch m.Header.Type { case syscall.IP_RECVTTL: cm.TTL = int(*(*byte)(unsafe.Pointer(&m.Data[:1][0]))) case syscall.IP_RECVDSTADDR: v := m.Data[:4] cm.Dst = net.IPv4(v[0], v[1], v[2], v[3]) case syscall.IP_RECVIF: sadl := (*syscall.SockaddrDatalink)(unsafe.Pointer(&m.Data[0])) cm.IfIndex = int(sadl.Index) } } return cm, nil }
func (s *OOBUnixConn) Read(p []byte) (n int, err error) { var oob [OOBMaxLength]byte n, oobn, _, _, err := s.ReadMsgUnix(p, oob[:]) if err == nil && n > 0 && oobn > 0 { scm, err := syscall.ParseSocketControlMessage(oob[0:oobn]) if err != nil { return n, err } s.m.Lock() for _, m := range scm { if m.Header.Level != syscall.SOL_SOCKET { continue } switch m.Header.Type { case syscall.SCM_RIGHTS: if fds, err := syscall.ParseUnixRights(&m); err == nil { for _, fd := range fds { // Note: We wrap the raw FDs inside an os.File just // once, early, to prevent double-free or leaking FDs. f := NewFile(fd) s.recvFiles = append(s.recvFiles, f) } } } } s.m.Unlock() } return n, err }
func parseControlMessage(b []byte) (*ControlMessage, error) { if len(b) == 0 { return nil, nil } cmsgs, err := syscall.ParseSocketControlMessage(b) if err != nil { return nil, os.NewSyscallError("parse socket control message", err) } cm := &ControlMessage{} for _, m := range cmsgs { if m.Header.Level != iana.ProtocolIP { continue } switch int(m.Header.Type) { case ctlOpts[ctlTTL].name: ctlOpts[ctlTTL].parse(cm, m.Data[:]) case ctlOpts[ctlDst].name: ctlOpts[ctlDst].parse(cm, m.Data[:]) case ctlOpts[ctlInterface].name: ctlOpts[ctlInterface].parse(cm, m.Data[:]) case ctlOpts[ctlPacketInfo].name: ctlOpts[ctlPacketInfo].parse(cm, m.Data[:]) } } return cm, nil }
func (r *FDReader) Read(b []byte) (int, error) { oob := make([]byte, 32) n, oobn, _, _, err := r.conn.ReadMsgUnix(b, oob) if err != nil { if n < 0 { n = 0 } return n, err } if oobn > 0 { messages, err := syscall.ParseSocketControlMessage(oob[:oobn]) if err != nil { return n, err } for _, m := range messages { fds, err := syscall.ParseUnixRights(&m) if err != nil { return n, err } // Set the CLOEXEC flag on the FDs so they won't be leaked into future forks for _, fd := range fds { if _, _, errno := syscall.Syscall(syscall.SYS_FCNTL, uintptr(fd), syscall.F_SETFD, syscall.FD_CLOEXEC); errno != 0 { return n, errno } r.FDs[r.fdCount] = fd r.fdCount++ } } } return n, nil }
func parseControlMessage(b []byte) (*ControlMessage, error) { if len(b) == 0 { return nil, nil } cmsgs, err := syscall.ParseSocketControlMessage(b) if err != nil { return nil, os.NewSyscallError("parse socket control message", err) } cm := &ControlMessage{} for _, m := range cmsgs { if m.Header.Level != ianaProtocolIPv6 { continue } switch m.Header.Type { case syscall.IPV6_TCLASS: cm.TrafficClass = int(*(*byte)(unsafe.Pointer(&m.Data[:1][0]))) case syscall.IPV6_HOPLIMIT: cm.HopLimit = int(*(*byte)(unsafe.Pointer(&m.Data[:1][0]))) case syscall.IPV6_PKTINFO: pi := (*syscall.Inet6Pktinfo)(unsafe.Pointer(&m.Data[0])) cm.Dst = pi.Addr[:] cm.IfIndex = int(pi.Ifindex) case syscall.IPV6_PATHMTU: mi := (*syscall.IPv6MTUInfo)(unsafe.Pointer(&m.Data[0])) cm.Dst = mi.Addr.Addr[:] cm.IfIndex = int(mi.Addr.Scope_id) cm.MTU = int(mi.Mtu) } } return cm, nil }
func mount(dir string, ready chan<- struct{}, errp *error) (fusefd *os.File, err error) { // linux mount is never delayed close(ready) fds, err := syscall.Socketpair(syscall.AF_FILE, syscall.SOCK_STREAM, 0) if err != nil { return nil, fmt.Errorf("socketpair error: %v", err) } defer syscall.Close(fds[0]) defer syscall.Close(fds[1]) cmd := exec.Command("fusermount", "--", dir) cmd.Env = append(os.Environ(), "_FUSE_COMMFD=3") writeFile := os.NewFile(uintptr(fds[0]), "fusermount-child-writes") defer writeFile.Close() cmd.ExtraFiles = []*os.File{writeFile} out, err := cmd.CombinedOutput() if len(out) > 0 || err != nil { return nil, fmt.Errorf("fusermount: %q, %v", out, err) } readFile := os.NewFile(uintptr(fds[1]), "fusermount-parent-reads") defer readFile.Close() c, err := net.FileConn(readFile) if err != nil { return nil, fmt.Errorf("FileConn from fusermount socket: %v", err) } defer c.Close() uc, ok := c.(*net.UnixConn) if !ok { return nil, fmt.Errorf("unexpected FileConn type; expected UnixConn, got %T", c) } buf := make([]byte, 32) // expect 1 byte oob := make([]byte, 32) // expect 24 bytes _, oobn, _, _, err := uc.ReadMsgUnix(buf, oob) scms, err := syscall.ParseSocketControlMessage(oob[:oobn]) if err != nil { return nil, fmt.Errorf("ParseSocketControlMessage: %v", err) } if len(scms) != 1 { return nil, fmt.Errorf("expected 1 SocketControlMessage; got scms = %#v", scms) } scm := scms[0] gotFds, err := syscall.ParseUnixRights(&scm) if err != nil { return nil, fmt.Errorf("syscall.ParseUnixRights: %v", err) } if len(gotFds) != 1 { return nil, fmt.Errorf("wanted 1 fd; got %#v", gotFds) } f := os.NewFile(uintptr(gotFds[0]), "/dev/fuse") return f, nil }
func readRequest(c *net.UnixConn) (*Request, error) { var l uint32 err := binary.Read(c, binary.BigEndian, &l) length := int(l) if err != nil { return nil, err } payload := make([]byte, length) n, err := c.Read(payload) if err != nil { return nil, err } else if n != length { return nil, fmt.Errorf("Payload was %d bytes rather than reported size of %d", n, length) } req := &Request{} err = json.Unmarshal(payload, req) if err != nil { return nil, err } if !req.HasFds { return req, nil } payload = make([]byte, 1) // TODO: does this buffer need to be configurable? oob := make([]byte, 8192) n, oobn, _, _, err := c.ReadMsgUnix(payload, oob) if err != nil && err != io.EOF { return nil, err } if n != 1 { return nil, fmt.Errorf("Error reading OOB filedescriptors") } oob = oob[0:oobn] scm, err := syscall.ParseSocketControlMessage(oob) if err != nil { return nil, fmt.Errorf("Error parsing socket control message: %v", err) } var fds []int for i := 0; i < len(scm); i++ { tfds, err := syscall.ParseUnixRights(&scm[i]) if err == syscall.EINVAL { continue // Wasn't a UnixRights Control Message } else if err != nil { return nil, fmt.Errorf("Error parsing unix rights: %v", err) } fds = append(fds, tfds...) } if len(fds) == 0 { return nil, fmt.Errorf("Failed to receive any FDs on a request with HasFds == true") } req.ReceivedFds = fds return req, nil }
func RetrieveOriginalDest(oob []byte) v2net.Destination { msgs, err := syscall.ParseSocketControlMessage(oob) if err != nil { return nil } for _, msg := range msgs { if msg.Header.Level == syscall.SOL_IP && msg.Header.Type == syscall.IP_ORIGDSTADDR { ip := v2net.IPAddress(msg.Data[4:8]) port := v2net.PortFromBytes(msg.Data[2:4]) return v2net.UDPDestination(ip, port) } } return nil }
func (c *Conn) ReadMessage() (m *Message, err error) { h, err := c.readHeader() if err != nil { return } log.Printf("ReadMessage: header = %s", h) m = &Message{ object: h.object(), opcode: h.opcode(), } if h.size() == 0 { return } p := make([]byte, h.size()) oob := make([]byte, 32) n, oobn, _, _, err := c.c.ReadMsgUnix(p, oob) if err != nil { return } if uint16(n) != h.size() { err = fmt.Errorf("expected %d bytes, got %d", h.size(), n) return } log.Printf("ReadMessage: n = %d, oobn = %d", n, oobn) m.p = bytes.NewBuffer(p) if oobn == 0 { return } oob = oob[:oobn] scms, err := syscall.ParseSocketControlMessage(oob) if err != nil { return } if len(scms) != 1 { err = fmt.Errorf("expected 1 SocketControlMessage, got %d", len(scms)) return } scm := scms[0] m.fds, err = syscall.ParseUnixRights(&scm) return }
func parseControlMessage(b []byte) (*ControlMessage, error) { if len(b) == 0 { return nil, nil } cmsgs, err := syscall.ParseSocketControlMessage(b) if err != nil { return nil, os.NewSyscallError("parse socket control message", err) } cm := &ControlMessage{} for _, m := range cmsgs { if m.Header.Level != ianaProtocolIP { continue } cm.parseControlMessage(&m) } return cm, nil }
// readIPv6Packet reads an IPv6 packet. For IPv6, the Read* functions do not // include the IP header, so the HOPLIMIT and destination address are read from // the control message data (see RFCs 3542 and 2292). The source address is // taken from the ReadMsgIP return values. func (c *IPHAConn) readIPv6Packet() (*packet, error) { b := recvBuffer oob := oobBuffer n, oobn, _, raddr, err := c.recvConn.ReadMsgIP(b, oob) if err != nil { return nil, err } scm, err := syscall.ParseSocketControlMessage(oob[:oobn]) if err != nil { return nil, err } var dst net.IP var ttl uint8 haveTTL := false for _, sc := range scm { if sc.Header.Level != syscall.IPPROTO_IPV6 { continue } switch sc.Header.Type { case syscall.IPV6_2292HOPLIMIT: if len(sc.Data) == 0 { return nil, fmt.Errorf("IPHAConn.readIPv6Packet: Invalid HOPLIMIT") } ttl = sc.Data[0] haveTTL = true case syscall.IPV6_2292PKTINFO: if len(sc.Data) < 16 { return nil, fmt.Errorf("IPHAConn.readIPv6Packet: Invalid destination address") } dst = net.IP(sc.Data[:16]) } } if !haveTTL { return nil, fmt.Errorf("IPHAConn.readIPv6Packet: HOPLIMIT not found") } if dst == nil { return nil, fmt.Errorf("IPHAConn.readIPv6Packet: Destination address not found") } return &packet{ src: raddr.IP, dst: dst, ttl: ttl, payload: b[:n], }, nil }
func (t *unixTransport) ReadNullByte() error { var oobBuf [4096]byte res := []byte{0} // There is currently no way to get at the underlying fd of a UnixConn, so // we can't set SO_PASSCRED on it. We can use File() to get a copy of it though. // Unfortunately that will not allow us to ReadMsgUnix, so we have to do that // manually file, err := t.File() if err != nil { return err } err = syscall.SetsockoptInt(int(file.Fd()), syscall.SOL_SOCKET, syscall.SO_PASSCRED, 1) if err != nil { return err } n, oobn, flags, _, err := readMsg(file, res, oobBuf[:]) if err != nil { return err } if n == 0 { return io.ErrUnexpectedEOF } if flags&syscall.MSG_CTRUNC != 0 { return errors.New("dbus: control data truncated") } msgs, err := syscall.ParseSocketControlMessage(oobBuf[:oobn]) if err != nil { return err } for _, msg := range msgs { cred, _ := syscall.ParseUnixCredentials(&msg) if cred != nil { t.hasPeerUid = true t.peerUid = cred.Uid } } return nil }
func readData(conn net.Conn) ([]Fd, int, error) { var b [2048]byte var oob [2048]byte var response Response n, oobn, _, _, err := conn.(*net.UnixConn).ReadMsgUnix(b[:], oob[:]) if err != nil { return nil, 0, fmt.Errorf("unix_socket: failed to read unix msg: %s (read: %d, %d)", err, n, oobn) } if n > 0 { err := json.Unmarshal(b[:n], &response) if err != nil { return nil, 0, fmt.Errorf("unix_socket: Unmarshal failed: %s", err) } if response.ErrMessage != "" { return nil, 0, errors.New(response.ErrMessage) } } else { return nil, 0, errors.New("unix_socket: No response received") } scms, err := syscall.ParseSocketControlMessage(oob[:oobn]) if err != nil { return nil, 0, fmt.Errorf("unix_socket: failed to parse socket control message: %s", err) } if len(scms) < 1 { return nil, 0, fmt.Errorf("unix_socket: no socket control messages sent") } scm := scms[0] fds, err := syscall.ParseUnixRights(&scm) if err != nil { return nil, 0, fmt.Errorf("unix_socket: failed to parse unix rights: %s", err) } files := make([]Fd, len(fds)) for i, fd := range fds { files[i] = os.NewFile(uintptr(fd), fmt.Sprintf("/dev/fake-fd-%d", i)) } return files, response.Pid, nil }
func extractFileDescriptorFromOOB(oob []byte) (int, error) { scms, err := syscall.ParseSocketControlMessage(oob) if err != nil { return -1, err } if len(scms) != 1 { return -1, errors.New(fmt.Sprintf("expected 1 SocketControlMessage; got scms = %#v", scms)) } scm := scms[0] gotFds, err := syscall.ParseUnixRights(&scm) if err != nil { return -1, err } if len(gotFds) != 1 { return -1, errors.New(fmt.Sprintf("wanted 1 fd; got %#v", gotFds)) } return gotFds[0], nil }
// TestUnixRightsRoundtrip tests that UnixRights, ParseSocketControlMessage, // and ParseUnixRights are able to successfully round-trip lists of file descriptors. func TestUnixRightsRoundtrip(t *testing.T) { testCases := [...][][]int{ {{42}}, {{1, 2}}, {{3, 4, 5}}, {{}}, {{1, 2}, {3, 4, 5}, {}, {7}}, } for _, testCase := range testCases { b := []byte{} var n int for _, fds := range testCase { // Last assignment to n wins n = len(b) + syscall.CmsgLen(4*len(fds)) b = append(b, syscall.UnixRights(fds...)...) } // Truncate b b = b[:n] scms, err := syscall.ParseSocketControlMessage(b) if err != nil { t.Fatalf("ParseSocketControlMessage: %v", err) } if len(scms) != len(testCase) { t.Fatalf("expected %v SocketControlMessage; got scms = %#v", len(testCase), scms) } for i, scm := range scms { gotFds, err := syscall.ParseUnixRights(&scm) if err != nil { t.Fatalf("ParseUnixRights: %v", err) } wantFds := testCase[i] if len(gotFds) != len(wantFds) { t.Fatalf("expected %v fds, got %#v", len(wantFds), gotFds) } for j, fd := range gotFds { if fd != wantFds[j] { t.Fatalf("expected fd %v, got %v", wantFds[j], fd) } } } } }
// Get receives file descriptors from a Unix domain socket. // // Num specifies the expected number of file descriptors in one message. // Internal files' names to be assigned are specified via optional filenames // argument. // // You need to close all files in the returned slice. The slice can be // non-empty even if this function returns an error. // // Use net.FileConn() if you're receiving a network connection. func Get(via *net.UnixConn, num int, filenames []string) ([]*os.File, error) { if num < 1 { return nil, nil } // get the underlying socket viaf, err := via.File() if err != nil { return nil, err } socket := int(viaf.Fd()) defer viaf.Close() // recvmsg buf := make([]byte, syscall.CmsgSpace(num*4)) _, _, _, _, err = syscall.Recvmsg(socket, nil, buf, 0) if err != nil { return nil, err } // parse control msgs var msgs []syscall.SocketControlMessage msgs, err = syscall.ParseSocketControlMessage(buf) // convert fds to files res := make([]*os.File, 0, len(msgs)) for i := 0; i < len(msgs) && err == nil; i++ { var fds []int fds, err = syscall.ParseUnixRights(&msgs[i]) for fi, fd := range fds { var filename string if fi < len(filenames) { filename = filenames[fi] } res = append(res, os.NewFile(uintptr(fd), filename)) } } return res, err }
func ReadWaylandMessage(conn *net.UnixConn) (*Message, error) { var buf [8]byte msg := Message{} control := make([]byte, 24) n, oobn, _, _, err := conn.ReadMsgUnix(buf[:], control) if err != nil { return nil, err } if n != 8 { return nil, errors.New("Unable to read message header.") } if oobn > 0 { if oobn > len(control) { panic("Unsufficient control msg buffer") } msg.control_msgs, err = syscall.ParseSocketControlMessage(control) if err != nil { panic(fmt.Sprintf("Control message parse error: %s", err.Error())) } } msg.Id = ProxyId(binary.LittleEndian.Uint32(buf[0:4])) msg.Opcode = uint32(binary.LittleEndian.Uint16(buf[4:6])) msg.size = uint32(binary.LittleEndian.Uint16(buf[6:8])) // subtract 8 bytes from header data := make([]byte, msg.size-8) n, err = conn.Read(data) if err != nil { return nil, err } if n != int(msg.size)-8 { return nil, errors.New("Invalid message size.") } msg.data = bytes.NewBuffer(data) return &msg, nil }
func ReadFile(c *net.UnixConn, timeout time.Duration) (*os.File, error) { oob := make([]byte, 64) if timeout > 0 { deadline := time.Now().Add(timeout) if err := c.SetReadDeadline(deadline); err != nil { return nil, err } } _, oobn, flags, _, err := c.ReadMsgUnix(nil, oob) if err != nil { return nil, err } if flags != 0 || oobn <= 0 { panic("ReadMsgUnix: flags != 0 || oobn <= 0") } // file descriptors are now open in this process scm, err := syscall.ParseSocketControlMessage(oob[:oobn]) if err != nil { return nil, err } if len(scm) != 1 { panic("invalid scm message") } fds, err := syscall.ParseUnixRights(&scm[0]) if err != nil { return nil, err } if len(fds) != 1 { panic("invalid scm message") } return os.NewFile(uintptr(fds[0]), ""), nil }
func (m *Message) parseControlData(data []byte) error { cmsgs, err := syscall.ParseSocketControlMessage(data) if err != nil { return err } for _, cmsg := range cmsgs { switch cmsg.Header.Type { case syscall.SCM_CREDENTIALS: cred, err := syscall.ParseUnixCredentials(&cmsg) if err != nil { return err } m.Ucred = cred case syscall.SCM_RIGHTS: fds, err := syscall.ParseUnixRights(&cmsg) if err != nil { return err } m.Fds = fds } } return nil }
func RecvFd(conn *net.UnixConn) (*os.File, error) { buf := make([]byte, 32) oob := make([]byte, 32) _, oobn, _, _, err := conn.ReadMsgUnix(buf, oob) if err != nil { return nil, fmt.Errorf("recvfd: err %v", err) } scms, err := syscall.ParseSocketControlMessage(oob[:oobn]) if err != nil { return nil, fmt.Errorf("recvfd: ParseSocketControlMessage failed %v", err) } if len(scms) != 1 { return nil, fmt.Errorf("recvfd: SocketControlMessage count not 1: %v", len(scms)) } scm := scms[0] fds, err := syscall.ParseUnixRights(&scm) if err != nil { return nil, fmt.Errorf("recvfd: ParseUnixRights failed %v", err) } if len(fds) != 1 { return nil, fmt.Errorf("recvfd: fd count not 1: %v", len(fds)) } return os.NewFile(uintptr(fds[0]), "passed-fd"), nil }
func parseControlMessage(b []byte) (*ControlMessage, error) { if len(b) == 0 { return nil, nil } cmsgs, err := syscall.ParseSocketControlMessage(b) if err != nil { return nil, os.NewSyscallError("parse socket control message", err) } cm := &ControlMessage{} for _, m := range cmsgs { if m.Header.Level != ianaProtocolIPv6 { continue } switch m.Header.Type { case sysSockopt2292HopLimit: cm.HopLimit = int(*(*byte)(unsafe.Pointer(&m.Data[:1][0]))) case sysSockopt2292PacketInfo: pi := (*sysPacketInfo)(unsafe.Pointer(&m.Data[0])) cm.IfIndex = int(pi.IfIndex) cm.Dst = pi.IP[:] } } return cm, nil }
func parseControlMessage(b []byte) (*ControlMessage, error) { cmsgs, err := syscall.ParseSocketControlMessage(b) if err != nil { return nil, os.NewSyscallError("parse socket control message", err) } if len(b) == 0 { return nil, nil } cm := &ControlMessage{} for _, m := range cmsgs { if m.Header.Level != ianaProtocolIP { continue } switch m.Header.Type { case syscall.IP_TTL: cm.TTL = int(*(*byte)(unsafe.Pointer(&m.Data[:1][0]))) case syscall.IP_PKTINFO: pi := (*syscall.Inet4Pktinfo)(unsafe.Pointer(&m.Data[0])) cm.IfIndex = int(pi.Ifindex) cm.Dst = net.IPv4(pi.Addr[0], pi.Addr[1], pi.Addr[2], pi.Addr[3]) } } return cm, nil }
// TestSCMCredentials tests the sending and receiving of credentials // (PID, UID, GID) in an ancillary message between two UNIX // sockets. The SO_PASSCRED socket option is enabled on the sending // socket for this to work. func TestSCMCredentials(t *testing.T) { fds, err := syscall.Socketpair(syscall.AF_LOCAL, syscall.SOCK_STREAM, 0) if err != nil { t.Fatalf("Socketpair: %v", err) } defer syscall.Close(fds[0]) defer syscall.Close(fds[1]) err = syscall.SetsockoptInt(fds[0], syscall.SOL_SOCKET, syscall.SO_PASSCRED, 1) if err != nil { t.Fatalf("SetsockoptInt: %v", err) } srv, err := net.FileConn(os.NewFile(uintptr(fds[0]), "")) if err != nil { t.Errorf("FileConn: %v", err) return } defer srv.Close() cli, err := net.FileConn(os.NewFile(uintptr(fds[1]), "")) if err != nil { t.Errorf("FileConn: %v", err) return } defer cli.Close() var ucred syscall.Ucred if os.Getuid() != 0 { ucred.Pid = int32(os.Getpid()) ucred.Uid = 0 ucred.Gid = 0 oob := syscall.UnixCredentials(&ucred) _, _, err := cli.(*net.UnixConn).WriteMsgUnix(nil, oob, nil) if err.(*net.OpError).Err != syscall.EPERM { t.Fatalf("WriteMsgUnix failed with %v, want EPERM", err) } } ucred.Pid = int32(os.Getpid()) ucred.Uid = uint32(os.Getuid()) ucred.Gid = uint32(os.Getgid()) oob := syscall.UnixCredentials(&ucred) // this is going to send a dummy byte n, oobn, err := cli.(*net.UnixConn).WriteMsgUnix(nil, oob, nil) if err != nil { t.Fatalf("WriteMsgUnix: %v", err) } if n != 0 { t.Fatalf("WriteMsgUnix n = %d, want 0", n) } if oobn != len(oob) { t.Fatalf("WriteMsgUnix oobn = %d, want %d", oobn, len(oob)) } oob2 := make([]byte, 10*len(oob)) n, oobn2, flags, _, err := srv.(*net.UnixConn).ReadMsgUnix(nil, oob2) if err != nil { t.Fatalf("ReadMsgUnix: %v", err) } if flags != 0 { t.Fatalf("ReadMsgUnix flags = 0x%x, want 0", flags) } if n != 1 { t.Fatalf("ReadMsgUnix n = %d, want 1 (dummy byte)", n) } if oobn2 != oobn { // without SO_PASSCRED set on the socket, ReadMsgUnix will // return zero oob bytes t.Fatalf("ReadMsgUnix oobn = %d, want %d", oobn2, oobn) } oob2 = oob2[:oobn2] if !bytes.Equal(oob, oob2) { t.Fatal("ReadMsgUnix oob bytes don't match") } scm, err := syscall.ParseSocketControlMessage(oob2) if err != nil { t.Fatalf("ParseSocketControlMessage: %v", err) } newUcred, err := syscall.ParseUnixCredentials(&scm[0]) if err != nil { t.Fatalf("ParseUnixCredentials: %v", err) } if *newUcred != ucred { t.Fatalf("ParseUnixCredentials = %+v, want %+v", newUcred, ucred) } }
// TestPassFD tests passing a file descriptor over a Unix socket. // // This test involved both a parent and child process. The parent // process is invoked as a normal test, with "go test", which then // runs the child process by running the current test binary with args // "-test.run=^TestPassFD$" and an environment variable used to signal // that the test should become the child process instead. func TestPassFD(t *testing.T) { if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" { passFDChild() return } tempDir, err := ioutil.TempDir("", "TestPassFD") if err != nil { t.Fatal(err) } defer os.RemoveAll(tempDir) fds, err := syscall.Socketpair(syscall.AF_LOCAL, syscall.SOCK_STREAM, 0) if err != nil { t.Fatalf("Socketpair: %v", err) } defer syscall.Close(fds[0]) defer syscall.Close(fds[1]) writeFile := os.NewFile(uintptr(fds[0]), "child-writes") readFile := os.NewFile(uintptr(fds[1]), "parent-reads") defer writeFile.Close() defer readFile.Close() cmd := exec.Command(os.Args[0], "-test.run=^TestPassFD$", "--", tempDir) cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"} cmd.ExtraFiles = []*os.File{writeFile} out, err := cmd.CombinedOutput() if len(out) > 0 || err != nil { t.Fatalf("child process: %q, %v", out, err) } c, err := net.FileConn(readFile) if err != nil { t.Fatalf("FileConn: %v", err) } defer c.Close() uc, ok := c.(*net.UnixConn) if !ok { t.Fatalf("unexpected FileConn type; expected UnixConn, got %T", c) } buf := make([]byte, 32) // expect 1 byte oob := make([]byte, 32) // expect 24 bytes closeUnix := time.AfterFunc(5*time.Second, func() { t.Logf("timeout reading from unix socket") uc.Close() }) _, oobn, _, _, err := uc.ReadMsgUnix(buf, oob) closeUnix.Stop() scms, err := syscall.ParseSocketControlMessage(oob[:oobn]) if err != nil { t.Fatalf("ParseSocketControlMessage: %v", err) } if len(scms) != 1 { t.Fatalf("expected 1 SocketControlMessage; got scms = %#v", scms) } scm := scms[0] gotFds, err := syscall.ParseUnixRights(&scm) if err != nil { t.Fatalf("syscall.ParseUnixRights: %v", err) } if len(gotFds) != 1 { t.Fatalf("wanted 1 fd; got %#v", gotFds) } f := os.NewFile(uintptr(gotFds[0]), "fd-from-child") defer f.Close() got, err := ioutil.ReadAll(f) want := "Hello from child process!\n" if string(got) != want { t.Errorf("child process ReadAll: %q, %v; want %q", got, err, want) } }
func mount(dir string, conf *mountConfig, ready chan<- struct{}, errp *error) (fusefd *os.File, err error) { // linux mount is never delayed close(ready) fds, err := syscall.Socketpair(syscall.AF_FILE, syscall.SOCK_STREAM, 0) if err != nil { return nil, fmt.Errorf("socketpair error: %v", err) } writeFile := os.NewFile(uintptr(fds[0]), "fusermount-child-writes") defer writeFile.Close() readFile := os.NewFile(uintptr(fds[1]), "fusermount-parent-reads") defer readFile.Close() cmd := exec.Command( "fusermount", "-o", conf.getOptions(), "--", dir, ) cmd.Env = append(os.Environ(), "_FUSE_COMMFD=3") cmd.ExtraFiles = []*os.File{writeFile} var wg sync.WaitGroup stdout, err := cmd.StdoutPipe() if err != nil { return nil, fmt.Errorf("setting up fusermount stderr: %v", err) } stderr, err := cmd.StderrPipe() if err != nil { return nil, fmt.Errorf("setting up fusermount stderr: %v", err) } if err := cmd.Start(); err != nil { return nil, fmt.Errorf("fusermount: %v", err) } helperErrCh := make(chan error, 1) wg.Add(2) go lineLogger(&wg, "mount helper output", neverIgnoreLine, stdout) go lineLogger(&wg, "mount helper error", handleFusermountStderr(helperErrCh), stderr) wg.Wait() if err := cmd.Wait(); err != nil { // see if we have a better error to report select { case helperErr := <-helperErrCh: // log the Wait error if it's not what we expected if !isBoringFusermountError(err) { log.Printf("mount helper failed: %v", err) } // and now return what we grabbed from stderr as the real // error return nil, helperErr default: // nope, fall back to generic message } return nil, fmt.Errorf("fusermount: %v", err) } c, err := net.FileConn(readFile) if err != nil { return nil, fmt.Errorf("FileConn from fusermount socket: %v", err) } defer c.Close() uc, ok := c.(*net.UnixConn) if !ok { return nil, fmt.Errorf("unexpected FileConn type; expected UnixConn, got %T", c) } buf := make([]byte, 32) // expect 1 byte oob := make([]byte, 32) // expect 24 bytes _, oobn, _, _, err := uc.ReadMsgUnix(buf, oob) scms, err := syscall.ParseSocketControlMessage(oob[:oobn]) if err != nil { return nil, fmt.Errorf("ParseSocketControlMessage: %v", err) } if len(scms) != 1 { return nil, fmt.Errorf("expected 1 SocketControlMessage; got scms = %#v", scms) } scm := scms[0] gotFds, err := syscall.ParseUnixRights(&scm) if err != nil { return nil, fmt.Errorf("syscall.ParseUnixRights: %v", err) } if len(gotFds) != 1 { return nil, fmt.Errorf("wanted 1 fd; got %#v", gotFds) } f := os.NewFile(uintptr(gotFds[0]), "/dev/fuse") return f, nil }
func (t *unixTransport) ReadMessage() (*Message, error) { var ( blen, hlen uint32 csheader [16]byte headers []header order binary.ByteOrder unixfds uint32 ) // To be sure that all bytes of out-of-band data are read, we use a special // reader that uses ReadUnix on the underlying connection instead of Read // and gathers the out-of-band data in a buffer. rd := &oobReader{conn: t.UnixConn} // read the first 16 bytes (the part of the header that has a constant size), // from which we can figure out the length of the rest of the message if _, err := io.ReadFull(rd, csheader[:]); err != nil { return nil, err } switch csheader[0] { case 'l': order = binary.LittleEndian case 'B': order = binary.BigEndian default: return nil, InvalidMessageError("invalid byte order") } // csheader[4:8] -> length of message body, csheader[12:16] -> length of // header fields (without alignment) binary.Read(bytes.NewBuffer(csheader[4:8]), order, &blen) binary.Read(bytes.NewBuffer(csheader[12:]), order, &hlen) if hlen%8 != 0 { hlen += 8 - (hlen % 8) } // decode headers and look for unix fds headerdata := make([]byte, hlen+4) copy(headerdata, csheader[12:]) if _, err := io.ReadFull(t, headerdata[4:]); err != nil { return nil, err } dec := newDecoder(bytes.NewBuffer(headerdata), order) dec.pos = 12 vs, err := dec.Decode(Signature{"a(yv)"}) if err != nil { return nil, err } Store(vs, &headers) for _, v := range headers { if v.Field == byte(FieldUnixFDs) { unixfds, _ = v.Variant.value.(uint32) } } all := make([]byte, 16+hlen+blen) copy(all, csheader[:]) copy(all[16:], headerdata[4:]) if _, err := io.ReadFull(rd, all[16+hlen:]); err != nil { return nil, err } if unixfds != 0 { if !t.hasUnixFDs { return nil, errors.New("dbus: got unix fds on unsupported transport") } // read the fds from the OOB data scms, err := syscall.ParseSocketControlMessage(rd.oob) if err != nil { return nil, err } if len(scms) != 1 { return nil, errors.New("dbus: received more than one socket control message") } fds, err := syscall.ParseUnixRights(&scms[0]) if err != nil { return nil, err } msg, err := DecodeMessage(bytes.NewBuffer(all)) if err != nil { return nil, err } // substitute the values in the message body (which are indices for the // array receiver via OOB) with the actual values for i, v := range msg.Body { if j, ok := v.(UnixFDIndex); ok { if uint32(j) >= unixfds { return nil, InvalidMessageError("invalid index for unix fd") } msg.Body[i] = UnixFD(fds[j]) } } return msg, nil } return DecodeMessage(bytes.NewBuffer(all)) }
// Up activates packet processing. // When the interface is down(IFF_UP is unset), opening the socket raise error. // This is because we have to call Up each time the state changed. func (self *NamedPort) Up() error { self.lock.Lock() defer self.lock.Unlock() if self.fd != -1 { return nil // already up } if self.flags&syscall.IFF_UP == 0 { return nil // not ready for up } if fd, err := syscall.Socket(syscall.AF_PACKET, syscall.SOCK_RAW, 0); err != nil { panic(err) } else { self.fd = fd } if err := func() error { if err := syscall.SetsockoptInt(self.fd, syscall.SOL_PACKET, syscall2.PACKET_AUXDATA, 1); err != nil { return err } if err := syscall.Bind(self.fd, &syscall.SockaddrLinklayer{ Protocol: syscall2.ETH_P_ALL, Ifindex: int(self.ifIndex), }); err != nil { return err } if sa, err := syscall.Getsockname(self.fd); err != nil { return err } else { self.hatype = sa.(*syscall.SockaddrLinklayer).Hatype switch self.hatype { default: panic("unsupported ARPHRD") case syscall.ARPHRD_IEEE80211_RADIOTAP: // ok case syscall.ARPHRD_ETHER: // ok case syscall2.ARPHRD_6LOWPAN: // ok } } return nil }(); err != nil { self.Down() return err } go func() { defer self.Down() buf := make([]byte, 32*1024) // enough for jumbo frame oob := make([]byte, syscall.CmsgSpace(20)) // msg_control, 20 = sizeof(auxdata) for { var frame Frame if bufN, oobN, flags, _, err := syscall.Recvmsg(self.fd, buf, oob, syscall.MSG_TRUNC); err != nil { if e, ok := err.(syscall.Errno); ok && e.Temporary() { continue } else { log.Print("Recvmsg", err) break } } else if bufN == 0 { break } else if bufN > len(buf) { log.Print("MSG_TRUNC") } else if flags&syscall.MSG_CTRUNC != 0 { log.Print("MSG_CTRUNC") } else { haveVlan := false var vlanTpid uint16 = 0x8100 var vlanTci uint16 if cmsgs, err := syscall.ParseSocketControlMessage(oob[:oobN]); err != nil { log.Print(err) return } else { for _, cmsg := range cmsgs { switch cmsg.Header.Type { case syscall2.PACKET_AUXDATA: aux := (*syscall2.Auxdata)(unsafe.Pointer(&cmsg.Data[0])) switch len(cmsg.Data) { case 20: if aux.Status&syscall2.TP_STATUS_VLAN_TPID_VALID != 0 { vlanTpid = aux.VlanTpid } case 18: // old format. pass default: log.Print("unexpected PACKET_AUXDATA") return } if aux.Status&syscall2.TP_STATUS_VLAN_VALID != 0 { haveVlan = true vlanTci = aux.VlanTci } } } } switch self.hatype { case syscall.ARPHRD_ETHER: var pkt []byte if haveVlan { pkt = make([]byte, bufN+4) copy(pkt[:12], buf[:12]) binary.BigEndian.PutUint16(pkt[12:], vlanTpid) binary.BigEndian.PutUint16(pkt[14:], vlanTci) copy(pkt[16:], buf[12:bufN]) } else { pkt = make([]byte, bufN) copy(pkt, buf) } frame = Frame{ Data: pkt, } case syscall.ARPHRD_IEEE80211_RADIOTAP: // NOTE: 802.11 + PACKET_AUXDATA unsupported bpkt := gopacket.NewPacket(buf[:bufN], layers.LayerTypeRadioTap, gopacket.Lazy) if rtl := bpkt.Layer(layers.LayerTypeRadioTap); rtl == nil { log.Print("radiotap layer error") } else if rt, ok := rtl.(*layers.RadioTap); !ok { log.Print("radiotap layer type error") } else { if f, err := FrameFromRadiotap(rt); err != nil { log.Print(err) } else { frame = f } } case syscall2.ARPHRD_6LOWPAN: pkt := make([]byte, 14+bufN) binary.BigEndian.PutUint16(pkt[12:], 0x86DD) copy(pkt[14:], buf[:bufN]) bpkt := gopacket.NewPacket(buf[:bufN], layers.LayerTypeIPv6, gopacket.Lazy) ip6 := bpkt.Layer(layers.LayerTypeIPv6).(*layers.IPv6) if ip6.DstIP.IsMulticast() { copy(pkt, []byte{0x33, 0x33}) copy(pkt[2:6], []byte(ip6.DstIP.To16())[12:16]) copy(pkt[6:], self.get6lowpanMac(ip6.SrcIP)) } else { copy(pkt[6:], self.get6lowpanMac(ip6.SrcIP)) copy(pkt, self.get6lowpanMac(ip6.DstIP)) } frame = Frame{ Data: pkt, } } if len(frame.Data) != 0 { func() { defer func() { if r := recover(); r != nil { // this may happen in socket race condition(rtnetlink and pf_packet). fmt.Println("dropping packet on closed ingress.") } }() self.ingress <- frame }() } } } }() return nil }