Kprobe

Read IP

Function to extract addrress of the socket using connect() system call

func readSockaddrFromBuff(buff io.Reader) (map[string]string, error) {
	res := make(map[string]string, 3)
	family, err := readInt16FromBuff(buff)
	if err != nil {
		return nil, err
	}
	res["sa_family"] = getSocketDomain(uint32(family))
	switch family {
	case 1: // AF_UNIX
		/*
			http://man7.org/linux/man-pages/man7/unix.7.html
			struct sockaddr_un {
					sa_family_t sun_family;     // AF_UNIX
					char        sun_path[108];  // Pathname
			};
		*/
		var sunPathBuf [108]byte
		err := binary.Read(buff, binary.LittleEndian, &sunPathBuf)
		if err != nil {
			return nil, fmt.Errorf("error parsing sockaddr_un: %v", err)
		}

		sunPath := ""
		for i, v := range sunPathBuf {
			if v == '\u0000' { // null termination
				sunPath = string(sunPathBuf[:i])
				break
			}
		}
		res["sun_path"] = sunPath
	case 2: // AF_INET
		/*
			http://man7.org/linux/man-pages/man7/ip.7.html
			struct sockaddr_in {
				sa_family_t    sin_family; // address family: AF_INET
				in_port_t      sin_port;   // port in network byte order
				struct in_addr sin_addr;   // internet address
			};
			struct in_addr {
				uint32_t       s_addr;     // address in network byte order
			};
		*/
		port, err := readUInt16BigendFromBuff(buff)
		if err != nil {
			return nil, fmt.Errorf("error parsing sockaddr_in: %v", err)
		}
		res["sin_port"] = strconv.Itoa(int(port))

		addr, err := readUInt32BigendFromBuff(buff)
		if err != nil {
			return nil, fmt.Errorf("error parsing sockaddr_in: %v", err)
		}
		res["sin_addr"] = readUint32IP(addr)
	case 10: // AF_INET6
		// https://man7.org/linux/man-pages/man7/ipv6.7.html
		port, err := readUInt16BigendFromBuff(buff)
		if err != nil {
			return nil, fmt.Errorf("error parsing sockaddr_in: %v", err)
		}

		res["sin_port"] = strconv.Itoa(int(port))
		_, err = readUInt32BigendFromBuff(buff)
		if err != nil {
			return nil, fmt.Errorf("error parsing IPv6 flow information: %v", err)
		}
		addr, err := readByteSliceFromBuff(buff, 16)
		if err != nil {
			return nil, fmt.Errorf("error parsing IPv6 IP: %v", err)
		}
		ipv6 := net.IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
		n := copy(ipv6, addr)
		if n != 16 {
			return nil, fmt.Errorf("error Converting bytes to IPv6, copied only %d bytes out of 16", n)
		}
		res["sin_addr"] = ipv6.String()
	}
	return res, nil
}

The code is a function called readSockaddrFromBuff, which **reads network socket address information from an io.Reader buffer and returns a map containing the extracted data.

Here’s a breakdown of the code:

  1. The function initializes a map called res to store the extracted socket address information. It also sets its initial capacity to 3.

  2. It reads a 16-bit integer value called family from the buffer using the readInt16FromBuff function. If there’s an error during reading, it returns the error.

The function assigns the string representation of the socket domain based on the family value to the sa_family key in the res map using the getSocketDomain function.

Depending on the value of family, the function proceeds with different cases to parse specific socket address structures.

Case 1: AF_UNIX – The code follows the structure of a Unix domain socket address. It reads a fixed-size buffer of 108 bytes representing the sun_path field, using binary.Read with little endian encoding. It then converts the null-terminated byte sequence into a string, assigning it to the sun_path key in the res map.

Case 2: AF_INET – The code follows the structure of an IPv4 socket address. It reads a 16-bit integer representing the port number (sin_port) using the readUInt16BigendFromBuff function and converts it to a string. It reads a 32-bit integer representing the IP address (sin_addr) using the readUInt32BigendFromBuff function and converts it to a string using the readUint32IP function. The sin_port and sin_addr values are then assigned to their respective keys in the res map.

Case 10: AF_INET6 – The code follows the structure of an IPv6 socket address. It reads a 16-bit integer representing the port number (sin_port) using the readUInt16BigendFromBuff function and converts it to a string. It ignores the next 32 bits representing flow information. It then reads a 16-byte slice representing the IPv6 address and converts it to a net.IP object. The resulting IPv6 address is assigned to the sin_addr key in the res map.

Finally, the function returns the res map containing the extracted socket address information, along with a nil error if the process was successful.

Note: The code references several utility functions (readInt16FromBuff, readUInt16BigendFromBuff, readUInt32BigendFromBuff, readByteSliceFromBuff, getSocketDomain, and readUint32IP), which are assumed to be defined elsewhere in the code or imported from external libraries.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top