| // Copyright 2017 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // Ad-hoc unsafe encoding/decoding of C data types used by the |
| // protocol libc talks to netstack. |
| |
| package main |
| |
| import ( |
| "fmt" |
| "log" |
| "syscall/zx" |
| "syscall/zx/mxerror" |
| "syscall/zx/zxsocket" |
| "unsafe" |
| |
| "github.com/google/netstack/tcpip" |
| ) |
| |
| const ( |
| c_sockaddr_in_len = int(unsafe.Sizeof(c_sockaddr_in{})) |
| c_sockaddr_in6_len = int(unsafe.Sizeof(c_sockaddr_in6{})) |
| c_sockaddr_storage_len = int(unsafe.Sizeof(c_sockaddr_storage{})) |
| c_mxrio_sockaddr_reply_len = int(unsafe.Sizeof(c_mxrio_sockaddr_reply{})) |
| c_fdio_socket_msg_hdr_len = int(unsafe.Sizeof(c_fdio_socket_msg_hdr{})) |
| ) |
| |
| func init() { |
| if c_sockaddr_storage_len < c_sockaddr_in_len { |
| panic("c_sockaddr_storage cannot hold c_sockaddr_in") |
| } |
| if c_sockaddr_storage_len < c_sockaddr_in6_len { |
| panic("c_sockaddr_storage cannot hold c_sockaddr_in6") |
| } |
| } |
| |
| func (v *c_mxrio_sockopt_req_reply) Decode(data []byte) error { |
| if uintptr(len(data)) < unsafe.Sizeof(c_mxrio_sockopt_req_reply{}) { |
| return fmt.Errorf("netstack: short c_mxrio_sockopt_req_reply: %d", len(data)) |
| } |
| req := (*c_mxrio_sockopt_req_reply)(unsafe.Pointer(&data[0])) |
| *v = *req |
| return nil |
| } |
| |
| func (v *c_mxrio_sockopt_req_reply) Encode(msg *zxsocket.Msg) { |
| r := (*c_mxrio_sockopt_req_reply)(unsafe.Pointer(&msg.Data[0])) |
| *r = *v |
| msg.Datalen = uint32(unsafe.Sizeof(*v)) |
| } |
| |
| func (v *c_mxrio_sockopt_tcp_info) Encode(out *c_mxrio_sockopt_req_reply) error { |
| r := (*c_mxrio_sockopt_tcp_info)(unsafe.Pointer(&out.optval[0])) |
| *r = *v |
| out.optlen = c_socklen(unsafe.Sizeof(*v)) |
| return nil |
| } |
| |
| func (v *c_mxrio_sockaddr_reply) Encode(msg *zxsocket.Msg) { |
| r := (*c_mxrio_sockaddr_reply)(unsafe.Pointer(&msg.Data[0])) |
| *r = *v |
| msg.Datalen = uint32(unsafe.Sizeof(*v)) |
| } |
| |
| func (v *c_ip_mreq) Decode(data []byte) error { |
| if uintptr(len(data)) < unsafe.Sizeof(c_ip_mreq{}) { |
| return fmt.Errorf("netstack: short c_ip_mreq: %d", len(data)) |
| } |
| req := (*c_ip_mreq)(unsafe.Pointer(&data[0])) |
| *v = *req |
| return nil |
| } |
| |
| func (v *c_ip_mreqn) Decode(data []byte) error { |
| if uintptr(len(data)) < unsafe.Sizeof(c_ip_mreqn{}) { |
| return fmt.Errorf("netstack: short c_ip_mreqn: %d", len(data)) |
| } |
| req := (*c_ip_mreqn)(unsafe.Pointer(&data[0])) |
| *v = *req |
| return nil |
| } |
| |
| func (v *c_netc_get_if_info) Encode(msg *zxsocket.Msg) { |
| r := (*c_netc_get_if_info)(unsafe.Pointer(&msg.Data[0])) |
| *r = *v |
| msg.Datalen = uint32(unsafe.Sizeof(*v)) |
| } |
| |
| func (v *c_netc_if_info) Encode(msg *zxsocket.Msg) { |
| r := (*c_netc_if_info)(unsafe.Pointer(&msg.Data[0])) |
| *r = *v |
| msg.Datalen = uint32(unsafe.Sizeof(*v)) |
| } |
| |
| // TODO: make these methods on c_sockaddr_storage |
| func writeSockaddrStorage4(dst *c_sockaddr_storage, src *c_sockaddr_in) c_socklen { |
| srcb := (*[unsafe.Sizeof(*src)]byte)(unsafe.Pointer(src))[:] |
| dstb := (*[unsafe.Sizeof(*dst)]byte)(unsafe.Pointer(dst))[:] |
| return c_socklen(copy(dstb, srcb)) |
| } |
| func writeSockaddrStorage6(dst *c_sockaddr_storage, src *c_sockaddr_in6) c_socklen { |
| srcb := (*[unsafe.Sizeof(*src)]byte)(unsafe.Pointer(src))[:] |
| dstb := (*[unsafe.Sizeof(*dst)]byte)(unsafe.Pointer(dst))[:] |
| return c_socklen(copy(dstb, srcb)) |
| } |
| func writeSockaddrStorage(dst *c_sockaddr_storage, a tcpip.FullAddress) (c_socklen, error) { |
| switch len(a.Addr) { |
| case 0, 4: |
| sockaddr := c_sockaddr_in{sin_family: AF_INET} |
| sockaddr.sin_port.setPort(a.Port) |
| copy(sockaddr.sin_addr[:], a.Addr) |
| return writeSockaddrStorage4(dst, &sockaddr), nil |
| case 16: |
| sockaddr := c_sockaddr_in6{sin6_family: AF_INET6} |
| sockaddr.sin6_port.setPort(a.Port) |
| copy(sockaddr.sin6_addr[:], a.Addr) |
| return writeSockaddrStorage6(dst, &sockaddr), nil |
| } |
| return 0, mxerror.Errorf(zx.ErrInvalidArgs, "write sockaddr: bad address len %d", len(a.Addr)) |
| } |
| |
| func (v c_in_port) port() uint16 { |
| return uint16(v[0])<<8 | uint16(v[1]) |
| } |
| |
| func (v *c_in_port) setPort(port uint16) { |
| v[0] = uint8(port >> 8) |
| v[1] = uint8(port) |
| } |
| |
| func readSockaddrIn(data []byte) (*tcpip.FullAddress, error) { |
| // TODO: recast in terms of c_sockaddr_storage |
| // TODO: split out the not-unsafe parts into socket_conv.go. |
| family := uint16(data[0]) | uint16(data[1])<<8 |
| if debug { |
| log.Printf("readSockaddrIn: family=%d", family) |
| } |
| switch family { |
| case AF_INET: |
| if len(data) < int(unsafe.Sizeof(c_sockaddr_in{})) { |
| return nil, mxerror.Errorf(zx.ErrInvalidArgs, "reading c_sockaddr_in: len(data)=%d too small", len(data)) |
| } |
| v := (*c_sockaddr_in)(unsafe.Pointer(&data[0])) |
| addr := &tcpip.FullAddress{ |
| Port: uint16(data[3]) | uint16(data[2])<<8, |
| } |
| // INADDR_ANY is represented as tcpip.Address(""). |
| if !isZeros(v.sin_addr[:]) { |
| addr.Addr = tcpip.Address(v.sin_addr[:]) |
| } |
| if debug { |
| log.Printf("readSockaddrIn: addr=%v", addr) |
| } |
| return addr, nil |
| case AF_INET6: |
| if len(data) < int(unsafe.Sizeof(c_sockaddr_in6{})) { |
| return nil, mxerror.Errorf(zx.ErrInvalidArgs, "reading c_sockaddr_in6: len(data)=%d too small", len(data)) |
| } |
| v := (*c_sockaddr_in6)(unsafe.Pointer(&data[0])) |
| addr := &tcpip.FullAddress{ |
| Port: uint16(data[3]) | uint16(data[2])<<8, |
| } |
| if !isZeros(v.sin6_addr[:]) { |
| addr.Addr = tcpip.Address(v.sin6_addr[:]) |
| } |
| if debug { |
| log.Printf("readSockaddrIn: addr=%v", addr) |
| } |
| return addr, nil |
| default: |
| return nil, mxerror.Errorf(zx.ErrInvalidArgs, "reading c_sockaddr: unknown family: %d", family) |
| } |
| } |
| |
| func readSocketMsgHdr(data []byte) (*tcpip.FullAddress, error) { |
| if len(data) < c_fdio_socket_msg_hdr_len { |
| return nil, mxerror.Errorf(zx.ErrInvalidArgs, "reading socket msg header: too short: %d", len(data)) |
| } |
| hdr := (*c_fdio_socket_msg_hdr)(unsafe.Pointer(&data[0])) |
| if hdr.addrlen == 0 { |
| return nil, nil |
| } |
| return readSockaddrIn(data) // first field of c_fdio_socket_msg_hdr is c_sockaddr_storage |
| } |
| |
| func writeSocketMsgHdr(data []byte, addr tcpip.FullAddress) error { |
| if len(data) < c_fdio_socket_msg_hdr_len { |
| return mxerror.Errorf(zx.ErrInvalidArgs, "writing socket msg header: too short: %d", len(data)) |
| } |
| hdr := (*c_fdio_socket_msg_hdr)(unsafe.Pointer(&data[0])) |
| l, err := writeSockaddrStorage(&hdr.addr, addr) |
| hdr.addrlen = l |
| hdr.flags = 0 |
| return err |
| } |