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 }