Advertisement
Guest User

Untitled

a guest
Jul 16th, 2018
92
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.32 KB | None | 0 0
  1. /*
  2. * Copyright (c) 2018 Politecnico di Torino
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16.  
  17. #pragma once
  18.  
  19. #include <string>
  20.  
  21. const std::string iptables_code_natlookup = R"(
  22. #include <uapi/linux/ip.h>
  23.  
  24. _INCLUDE_PROTO_CONSTANTS
  25.  
  26. _INCLUDE_STRUCT_ICMPHDR
  27.  
  28. _INCLUDE_NAT_ENUM
  29.  
  30. _INCLUDE_STRUCT_PACKETHEADERS
  31.  
  32. _INCLUDE_STRUCT_CT_KV
  33.  
  34. _INCLUDE_STRUCT_NAT_DECISION
  35.  
  36. _INCLUDE_STRUCT_NAT_KV
  37.  
  38. // TODO
  39. // define and implement the NAT table
  40.  
  41. BPF_TABLE("extern", struct ct_k, struct ct_v, connections, 10240);
  42.  
  43. BPF_TABLE("extern", int, struct packetHeaders, packet, 1);
  44.  
  45. // TODO Study the possibility to use array intead of hash
  46. // for code porting form pbforwarder, and for simplicity
  47. // we choose to use hash maps
  48. #if _INGRESS_LOGIC
  49. BPF_TABLE("hash", uint32_t, struct nat_v, natrules_DIRECTION, 64);
  50. #endif
  51.  
  52. #if _EGRESS_LOGIC
  53. BPF_TABLE("hash", uint32_t, struct nat_v, natrules_DIRECTION, 64);
  54. #endif
  55.  
  56. #undef HARDCODED_NAT_RULE
  57. // #define HARDCODED_NAT_RULE
  58.  
  59. // This is the percpu array containing the NAT decision. Subsequent NAT mdoules just lookup this value
  60. BPF_TABLE("extern", int, struct nat_decision, natDecision, 1);
  61.  
  62. static int handle_rx(struct CTXTYPE *ctx, struct pkt_metadata *md) {
  63. // NAT parts
  64. // Part 1: Nat.cpp, Iptables_Nat_dp.h: lookup in the CT table
  65. // Part 2: NatLookup.cpp, Iptables_NatLookup_dp.h: lookup in the NAT table
  66. // Part 3: NatAction.cpp, Iptables_NatAction_dp.h: apply NAT
  67. // ---------------------------
  68.  
  69. // NAT part 2: lookup the NAT table to check if any rule applies to the packet
  70.  
  71. // In part 1, a lookup in the CT table is performed
  72. // We get here in 2 cases
  73. // 1) the CT table does not have an entry for this packet
  74. // decision->entryPresent = 0
  75. // 2) the CT table contains an entry for this packet with trans_type UNDEF_NAT
  76. // decision->entryPresent = 1
  77. // decision->updateEntry = 1
  78.  
  79. // entryPresent & updateEntry are managed by first module.
  80.  
  81. // Either way we have to lookup the nat rule table: the outcome can be SRC, DST
  82. // or NO_NAT. If the resulting trans_type is NO_NAT (no matching entry in the NAT table),
  83. // we have to go to part 3 anyway, because only part 3 can update the CT table
  84.  
  85. // In practice, this means we can ignore the decision here, because if we are here we
  86. // have to lookup, for sure. After the lookup we update decision->newIp, decision->newPort,
  87. // decision->match and go to part 3
  88.  
  89. // This is only a lookup module, no change whatsoever is applied to the packet here.
  90. // The decision will be read by part 3, which will perform the necessary actions
  91.  
  92. iovnet_log(ctx, LOG_TRACE, "[NAT RULE LOOKUP _DIRECTION] Received packet ");
  93.  
  94. int k = 0;
  95. struct packetHeaders *pkt = packet.lookup(&k);
  96. if (pkt == NULL) {
  97. // Not possible
  98. return RX_DROP;
  99. }
  100.  
  101. struct nat_decision *decision = natDecision.lookup(&k);
  102. if (decision == NULL) {
  103. // Not possible
  104. return RX_DROP;
  105. }
  106.  
  107. iovnet_log(ctx, LOG_TRACE, "[NAT RULE LOOKUP _DIRECTION] Nr Rules: _RULES ");
  108.  
  109. #ifdef HARDCODED_NAT_RULE
  110.  
  111. #if _INGRESS_LOGIC
  112.  
  113. // Testing with static mapping: ../../test/local_test6_iptables.sh
  114. if (pkt->l4proto == IPPROTO_TCP) {
  115. iovnet_log(ctx, LOG_TRACE, "[NAT RULE LOOKUP _DIRECTION] Packet is TCP");
  116.  
  117. if (bpf_ntohs(pkt->dstPort) == 60123) {
  118. decision->match = DST;
  119. decision->newIp = pkt->dstIp;
  120. decision->newPort = bpf_htons(60321);
  121.  
  122. iovnet_log(ctx, LOG_TRACE, "[NAT RULE LOOKUP _DIRECTION] TCP srcPort: %d, dstPort: %d", bpf_ntohs(pkt->srcPort), bpf_ntohs(pkt->dstPort));
  123. }
  124.  
  125. else {
  126. // Until we make it work
  127. decision->match = NO_NAT;
  128. decision->entryPresent = 1;
  129. decision->updateEntry = 0;
  130. }
  131. } else {
  132. // Until we make it work
  133. decision->match = NO_NAT;
  134. decision->entryPresent = 1;
  135. decision->updateEntry = 0;
  136. }
  137. #endif
  138. #if _EGRESS_LOGIC
  139. iovnet_log(ctx, LOG_TRACE, "[NAT RULE LOOKUP _DIRECTION] Egress logic. No nat rule.");
  140. // Until we make it work
  141. decision->match = NO_NAT;
  142. decision->entryPresent = 1;
  143. decision->updateEntry = 0;
  144. #endif
  145.  
  146. #endif
  147.  
  148. #ifndef HARDCODED_NAT_RULE
  149.  
  150. #define BITS_PER_WORD (sizeof(uint32_t) * 8)
  151. #define BIT_OFFSET(b) ((b) % BITS_PER_WORD)
  152. #define GET_BIT(word, n) (word & (1ULL << BIT_OFFSET(n)))
  153.  
  154. // regular algorithm
  155.  
  156. struct nat_v *nat_value = 0;
  157.  
  158. #if _RULES == 0
  159. iovnet_log(ctx, LOG_DEBUG, "[NAT RULE LOOKUP _DIRECTION] No natting rules. ");
  160. // todo what to do?
  161. goto NOT_MATCHED;
  162. #elif _RULES == 1
  163. int key = 0;
  164. nat_value = natrules_DIRECTION.lookup(&key);
  165. if (nat_value == NULL){
  166. // No rule with this ID
  167. goto NOT_MATCHED;
  168. }
  169. #elif _RULES > 1
  170. #pragma unroll
  171. for (int i = 0; i < _RULES; i++) {
  172. int key = i;
  173. nat_value = natrules_DIRECTION.lookup(&key);
  174. if (nat_value == NULL){
  175. // No rule with this ID
  176. goto NOT_MATCHED;
  177. }
  178. #endif
  179.  
  180. // TODO: improve, inject only needed field match
  181.  
  182. /* Src IP Match */
  183. iovnet_log(ctx, LOG_TRACE, "[NAT RULE LOOKUP _DIRECTION] SrcIp match 0x%x pkt:%I rule:%I ", GET_BIT(nat_value->bitmask, 0), pkt->srcIp, nat_value->srcIp );
  184. if (GET_BIT(nat_value->bitmask, 0)) {
  185. if (pkt->srcIp != nat_value->srcIp)
  186. goto NOT_MATCHED;
  187. }
  188.  
  189. /* Dst IP Match */
  190. iovnet_log(ctx, LOG_TRACE, "[NAT RULE LOOKUP _DIRECTION] DstIp match 0x%x pkt:%I rule:%I ", GET_BIT(nat_value->bitmask, 1), pkt->dstIp, nat_value->dstIp );
  191. if (GET_BIT(nat_value->bitmask, 1)) {
  192. if (pkt->dstIp != nat_value->dstIp)
  193. goto NOT_MATCHED;
  194. }
  195.  
  196. /* Src Port Match */
  197. iovnet_log(ctx, LOG_TRACE, "[NAT RULE LOOKUP _DIRECTION] SrcPrt match 0x%x pkt:%P rule:%P ", GET_BIT(nat_value->bitmask, 2), pkt->srcPort, nat_value->srcPort );
  198. if (GET_BIT(nat_value->bitmask, 2)) {
  199. if (pkt->srcPort != nat_value->srcPort)
  200. goto NOT_MATCHED;
  201. }
  202.  
  203. /* Dst Port Match */
  204. iovnet_log(ctx, LOG_TRACE, "[NAT RULE LOOKUP _DIRECTION] DstPrt match 0x%x pkt:%P rule:%P ", GET_BIT(nat_value->bitmask, 3), pkt->dstPort, nat_value->dstPort );
  205. if (GET_BIT(nat_value->bitmask, 3)) {
  206. if (pkt->dstPort != nat_value->dstPort)
  207. goto NOT_MATCHED;
  208. }
  209.  
  210. /* L4 Proto Match */
  211. iovnet_log(ctx, LOG_TRACE, "[NAT RULE LOOKUP _DIRECTION] L4Proto match 0x%x pkt:0x%x rule:0x%x ", GET_BIT(nat_value->bitmask, 4), pkt->l4proto, nat_value->l4proto );
  212. if (GET_BIT(nat_value->bitmask, 4)) {
  213. if (pkt->l4proto != nat_value->l4proto)
  214. goto NOT_MATCHED;
  215. }
  216.  
  217. // /* TCP Flags Match */
  218. // if (GET_BIT(nat_value->bitmask, 5)) {
  219. // if (pkt->flags != nat_value->tcpFlags)
  220. // goto NOT_MATCHED;
  221. // }
  222.  
  223. #if _INGRESS_LOGIC
  224. /* In Interface Match */
  225. iovnet_log(ctx, LOG_TRACE, "[NAT RULE LOOKUP _DIRECTION] InPort match 0x%x pkt:0x%x rule:0x%x ", GET_BIT(nat_value->bitmask, 6), md->in_port, nat_value->inIface );
  226. if (GET_BIT(nat_value->bitmask, 6)) {
  227. if (md->in_port != nat_value->inIface)
  228. goto NOT_MATCHED;
  229. }
  230. #endif
  231.  
  232. #if _EGRESS_LOGIC
  233. /* In Interface Match */
  234. iovnet_log(ctx, LOG_TRACE, "[NAT RULE LOOKUP _DIRECTION] OutPort match 0x%x pkt:0x%x rule:0x%x ", GET_BIT(nat_value->bitmask, 7), md->in_port, nat_value->outIface );
  235. if (GET_BIT(nat_value->bitmask, 7)) {
  236. if (md->in_port != nat_value->outIface)
  237. goto NOT_MATCHED;
  238. }
  239. #endif
  240.  
  241. // RULE MATCHED
  242.  
  243. decision->match = nat_value->type;
  244. decision->newIp = nat_value->newIp;
  245. // TODO in case of SNAT, newPort is not assigned. It should be provided by algorithm for
  246. // selecting first free port. This should be implemented in the following module.
  247. decision->newPort = nat_value->newPort;
  248.  
  249.  
  250. //TODO: Implement SNAT find first free port!
  251. // if rule == SNAT
  252. // newPort = findFirstFreePort();
  253.  
  254. iovnet_log(ctx, LOG_TRACE, "[NAT RULE LOOKUP _DIRECTION] RULE Matched! matchTyper: 0x%x newIp: %I nePort: %P ", nat_value->type, nat_value->newIp, nat_value->newPort );
  255.  
  256. goto NEXT_PROGRAM;
  257.  
  258. NOT_MATCHED:;
  259. #if _RULES > 1
  260. } // Close for
  261. #endif
  262.  
  263. decision->match = NO_NAT;
  264.  
  265. #endif
  266.  
  267. NEXT_PROGRAM:;
  268. call_bpf_program(ctx, _NAT_ACTION);
  269. return RX_DROP;
  270. }
  271. )";
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement