github.com/aporeto-inc/trireme-lib@v10.358.0+incompatible/controller/internal/enforcer/nfqdatapath/afinetrawsocket/afinetrawsocket.go (about)

     1  // +build linux
     2  
     3  package afinetrawsocket
     4  
     5  import (
     6  	"fmt"
     7  	"io/ioutil"
     8  	"strconv"
     9  	"strings"
    10  	"syscall"
    11  
    12  	"go.aporeto.io/enforcerd/trireme-lib/controller/pkg/packet"
    13  )
    14  
    15  type socketv4 struct {
    16  	fd     int
    17  	insock *syscall.SockaddrInet4
    18  }
    19  
    20  type socketv6 struct {
    21  	fd     int
    22  	insock *syscall.SockaddrInet6
    23  }
    24  
    25  type rawsocket struct {
    26  	insockv4 *socketv4
    27  	insockv6 *socketv6
    28  }
    29  
    30  const (
    31  	// RawSocketMark is the mark asserted on all packet sent out of this socket
    32  	RawSocketMark = 0x63
    33  	// NetworkRawSocketMark is the mark on packet egressing
    34  	//the raw socket coming in from network
    35  	NetworkRawSocketMark = 0x40000063
    36  	//ApplicationRawSocketMark is the mark on packet egressing
    37  	//the raw socket coming from application
    38  	ApplicationRawSocketMark = 0x40000062
    39  )
    40  
    41  // SocketWriter interface exposes an interface to write and close sockets
    42  type SocketWriter interface {
    43  	WriteSocket(buf []byte, version packet.IPver, data packet.PlatformMetadata) error
    44  }
    45  
    46  // CreateSocket returns a handle to SocketWriter interface
    47  func CreateSocket(mark int, deviceName string) (SocketWriter, error) {
    48  	var sockv6 *socketv6
    49  	var sockv4 *socketv4
    50  	var err error
    51  	createSocketv4 := func() (*socketv4, error) {
    52  
    53  		fd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, syscall.IPPROTO_UDP)
    54  		if err != nil {
    55  			return nil, fmt.Errorf("received error %s while open ipv4 socket", err)
    56  		}
    57  
    58  		if err := syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_MARK, mark); err != nil {
    59  			syscall.Close(fd) // nolint: errcheck
    60  			return nil, fmt.Errorf("received error %s while setting socket Option SO_MARK", err)
    61  		}
    62  
    63  		if err := syscall.SetsockoptInt(fd, syscall.IPPROTO_IP, syscall.IP_HDRINCL, 0); err != nil {
    64  			syscall.Close(fd) // nolint: errcheck
    65  			return nil, fmt.Errorf("received error %s while setting socket Option IP_HDRINCL", err)
    66  		}
    67  
    68  		if err := syscall.SetsockoptInt(fd, syscall.IPPROTO_IP, syscall.IP_MTU_DISCOVER, syscall.IP_PMTUDISC_DONT); err != nil {
    69  			syscall.Close(fd) // nolint: errcheck
    70  			return nil, fmt.Errorf("received error %s while setting socket Option IP_PMTUDISC_DONT", err)
    71  		}
    72  
    73  		return &socketv4{
    74  			fd: fd,
    75  			insock: &syscall.SockaddrInet4{
    76  				Port: 0,
    77  			},
    78  		}, nil
    79  	}
    80  
    81  	createSocketv6 := func() (*socketv6, error) {
    82  
    83  		fd, err := syscall.Socket(syscall.AF_INET6, syscall.SOCK_RAW, syscall.IPPROTO_UDP)
    84  		if err != nil {
    85  			return nil, fmt.Errorf("received error %s while open ipv6 socket", err)
    86  		}
    87  
    88  		if err := syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_MARK, mark); err != nil {
    89  			syscall.Close(fd) // nolint: errcheck
    90  			return nil, fmt.Errorf("received error %s while setting socket Option SO_MARK", err)
    91  		}
    92  
    93  		if err := syscall.SetsockoptInt(fd, syscall.IPPROTO_IPV6, syscall.IP_HDRINCL, 0); err != nil {
    94  			syscall.Close(fd) // nolint: errcheck
    95  			return nil, fmt.Errorf("received error %s while setting socket Option IP_HDRINCL", err)
    96  		}
    97  
    98  		if err := syscall.SetsockoptInt(fd, syscall.IPPROTO_IPV6, syscall.IPV6_MTU_DISCOVER, syscall.IPV6_PMTUDISC_DONT); err != nil {
    99  			syscall.Close(fd) // nolint: errcheck
   100  			return nil, fmt.Errorf("received error %s while setting socket Option IP_PMTUDISC_DONT ipv6", err)
   101  		}
   102  
   103  		return &socketv6{
   104  			fd: fd,
   105  			insock: &syscall.SockaddrInet6{
   106  				Port: 0,
   107  			},
   108  		}, nil
   109  	}
   110  
   111  	sockv4, err = createSocketv4()
   112  	if err != nil {
   113  		return nil, err
   114  	}
   115  	if IsIpv6Supported() {
   116  		sockv6, err = createSocketv6()
   117  		if err != nil {
   118  			return nil, err
   119  		}
   120  	}
   121  	return &rawsocket{
   122  		insockv4: sockv4,
   123  		insockv6: sockv6,
   124  	}, nil
   125  }
   126  
   127  func (sock *rawsocket) WriteSocket(buf []byte, version packet.IPver, data packet.PlatformMetadata) error {
   128  	// copy the dest addr
   129  	if version == packet.V4 {
   130  		copy(sock.insockv4.insock.Addr[:], buf[16:20])
   131  		if err := syscall.Sendto(sock.insockv4.fd, buf[20:], 0, sock.insockv4.insock); err != nil {
   132  			return fmt.Errorf("received error %s while sending to socket", err)
   133  		}
   134  	} else if sock.insockv6 != nil {
   135  
   136  		copy(sock.insockv6.insock.Addr[:], buf[24:40])
   137  		if err := syscall.Sendto(sock.insockv6.fd, buf[40:], 0, sock.insockv6.insock); err != nil {
   138  			return fmt.Errorf("received error %s while sending to socket", err)
   139  		}
   140  
   141  	}
   142  
   143  	return nil
   144  }
   145  
   146  // IsIpv6Supported returns true if the system supports ipv6 else returns false
   147  func IsIpv6Supported() bool {
   148  	ipv6ConfPath := "/proc/sys/net/ipv6/conf/all/disable_ipv6"
   149  	data, err := ioutil.ReadFile(ipv6ConfPath)
   150  	if err != nil {
   151  		return false
   152  	}
   153  	val, err := strconv.Atoi(strings.Trim(string(data), "\n"))
   154  	if err != nil {
   155  		return false
   156  	}
   157  	if val == 1 {
   158  		return false
   159  	}
   160  	return true
   161  }