github.com/aporeto-inc/trireme-lib@v10.358.0+incompatible/controller/internal/supervisor/iptablesctrl/icmp_linux.go (about)

     1  // +build !rhel6
     2  
     3  package iptablesctrl
     4  
     5  /*
     6  #cgo linux LDFLAGS: -L/tmp -lpcap
     7  #include<string.h>
     8  #include<stdlib.h>
     9  #include<pcap.h>
    10  
    11  char bpf_program[1500];
    12  
    13  char *compileBPF(const char *expr) {
    14  	struct bpf_program program;
    15  	struct bpf_insn *ins;
    16          char buf[100];
    17  	int i, dlt = DLT_RAW;
    18  
    19  	if (pcap_compile_nopcap(65535, dlt, &program, expr, 1,
    20  				PCAP_NETMASK_UNKNOWN)) {
    21  		return NULL;
    22  	}
    23  
    24          if (program.bf_len > 63) {
    25                 return NULL;
    26          }
    27  
    28  	sprintf(bpf_program, "%d,", program.bf_len);
    29  	ins = program.bf_insns;
    30  
    31  
    32  	for (i = 0; i < program.bf_len-1; ++ins, ++i) {
    33                  sprintf(buf, "%u %u %u %u,", ins->code, ins->jt, ins->jf, ins->k);
    34                  strcat(bpf_program, buf);
    35          }
    36  
    37          sprintf(buf, "%u %u %u %u", ins->code, ins->jt, ins->jf, ins->k);
    38          strcat(bpf_program, buf);
    39  	pcap_freecode(&program);
    40  	return bpf_program;
    41  }
    42  */
    43  import "C"
    44  import (
    45  	"strings"
    46  	"sync"
    47  	"unsafe"
    48  
    49  	"go.aporeto.io/gaia/protocols"
    50  )
    51  
    52  func icmpRule(icmpTypeCode string, policyRestrictions []string) []string {
    53  	bytecode := getBPFCode(icmpTypeCode, policyRestrictions)
    54  	return []string{"-m", "bpf", "--bytecode", bytecode}
    55  }
    56  
    57  func getICMPv6() string {
    58  
    59  	genString := func(icmpType string, icmpCode string) string {
    60  		return "(icmp6[0] == " + icmpType + " and icmp6[1] == " + icmpCode + ")"
    61  	}
    62  
    63  	routerSolicitation := genString("133", "0")
    64  	routerAdvertisement := genString("134", "0")
    65  	neighborSolicitation := genString("135", "0")
    66  	neighborAdvertisement := genString("136", "0")
    67  	inverseNeighborSolicitation := genString("141", "0")
    68  	inverseNeighborAdvertisement := genString("142", "0")
    69  
    70  	s := []string{routerSolicitation,
    71  		routerAdvertisement,
    72  		neighborSolicitation,
    73  		neighborAdvertisement,
    74  		inverseNeighborSolicitation,
    75  		inverseNeighborAdvertisement}
    76  
    77  	return strings.Join(s, " or ")
    78  }
    79  
    80  var lock sync.Mutex
    81  
    82  func compileExprToBPF(expr string) string {
    83  	lock.Lock()
    84  	defer lock.Unlock()
    85  
    86  	cExpr := C.CString(expr)
    87  	defer C.free(unsafe.Pointer(cExpr))
    88  
    89  	bpfString := C.compileBPF(cExpr)
    90  
    91  	return C.GoString(bpfString)
    92  }
    93  
    94  func getBPFCode(icmpTypeCode string, policyRestriction []string) string {
    95  	bytecode := compileExprToBPF(generateExpr(icmpTypeCode, policyRestriction))
    96  
    97  	// bpf can return empty bytecodes as it is smart to know the expression
    98  	// doesn't have a match. eg. 'icmp and icmp6'. In that case generate
    99  	// and expression which doesn't match anything but bpf still generates byte code for.
   100  	if bytecode == "" {
   101  		bytecode = compileExprToBPF("icmp[0] > 5 and icmp[0] < 5")
   102  	}
   103  
   104  	return bytecode
   105  }
   106  
   107  func generateExpr(icmpTypeCode string, policyRestriction []string) string {
   108  
   109  	processList := func(vs []string, f func(string) string) []string {
   110  		vals := make([]string, len(vs))
   111  
   112  		for i, v := range vs {
   113  			vals[i] = f(v)
   114  		}
   115  
   116  		return vals
   117  	}
   118  
   119  	leafProcessElement := func(f func() string) string {
   120  		return "(" + f() + ")"
   121  	}
   122  
   123  	genProto := func(val string) string {
   124  		return leafProcessElement(func() string { return val })
   125  	}
   126  
   127  	genType := func(proto, icmpType string) string {
   128  
   129  		switch strings.ToUpper(proto) {
   130  		case protocols.L4ProtocolICMP:
   131  			return leafProcessElement(func() string { return "icmp[0] == " + icmpType })
   132  		default:
   133  			return leafProcessElement(func() string { return "icmp6[0] == " + icmpType })
   134  		}
   135  	}
   136  
   137  	genCodes := func(proto, val string) string {
   138  
   139  		genCode := func(v string) string {
   140  
   141  			switch splits := strings.Split(v, ":"); len(splits) {
   142  			case 1:
   143  				switch strings.ToUpper(proto) {
   144  				case protocols.L4ProtocolICMP:
   145  					return leafProcessElement(func() string { return "icmp[1] == " + v })
   146  				default:
   147  					return leafProcessElement(func() string { return "icmp6[1] == " + v })
   148  				}
   149  			default:
   150  				min := splits[0]
   151  				max := splits[1]
   152  
   153  				switch strings.ToUpper(proto) {
   154  				case protocols.L4ProtocolICMP:
   155  					minExpr := leafProcessElement(func() string { return "icmp[1] >= " + min })
   156  					maxExpr := leafProcessElement(func() string { return "icmp[1] <= " + max })
   157  					return leafProcessElement(func() string { return minExpr + " and " + maxExpr })
   158  				default:
   159  					minExpr := leafProcessElement(func() string { return "icmp6[1] >= " + min })
   160  					maxExpr := leafProcessElement(func() string { return "icmp6[1] <= " + max })
   161  					return leafProcessElement(func() string { return minExpr + " and " + maxExpr })
   162  				}
   163  			}
   164  		}
   165  
   166  		splits := strings.Split(val, ",")
   167  		vals := processList(splits, genCode)
   168  
   169  		return leafProcessElement(func() string { return strings.Join(vals, "or") })
   170  	}
   171  
   172  	processSingleTypeCode := func(icmpTypeCode string) string {
   173  		expr := ""
   174  		splits := strings.Split(icmpTypeCode, "/")
   175  		proto := splits[0]
   176  
   177  		for i, val := range splits {
   178  			switch i {
   179  			case 0:
   180  				expr = genProto(val)
   181  			case 1:
   182  				expr = leafProcessElement(func() string { return expr + " and " + genType(proto, val) })
   183  			case 2:
   184  				expr = leafProcessElement(func() string { return expr + " and " + genCodes(proto, val) })
   185  			}
   186  		}
   187  
   188  		return expr
   189  	}
   190  
   191  	combined := []string{}
   192  	bpfExprForPolicyRestriction := strings.Join(processList(policyRestriction, processSingleTypeCode), " or ")
   193  
   194  	if bpfExprForPolicyRestriction != "" {
   195  		bpfExprForPolicyRestriction = leafProcessElement(func() string { return bpfExprForPolicyRestriction })
   196  		combined = []string{bpfExprForPolicyRestriction}
   197  	}
   198  
   199  	bpfExprForExtNet := processSingleTypeCode(icmpTypeCode)
   200  
   201  	combined = append(combined, bpfExprForExtNet)
   202  	return leafProcessElement(func() string { return strings.Join(combined, " and ") })
   203  }
   204  
   205  var icmpAllow = func() string {
   206  	return compileExprToBPF(getICMPv6())
   207  }
   208  
   209  func allowICMPv6(cfg *ACLInfo) {
   210  	cfg.ICMPv6Allow = icmpAllow()
   211  }