Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * Copyright (c) 2018 Politecnico di Torino
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #pragma once
- #include <string>
- const std::string iptables_code_natlookup = R"(
- #include <uapi/linux/ip.h>
- _INCLUDE_PROTO_CONSTANTS
- _INCLUDE_STRUCT_ICMPHDR
- _INCLUDE_NAT_ENUM
- _INCLUDE_STRUCT_PACKETHEADERS
- _INCLUDE_STRUCT_CT_KV
- _INCLUDE_STRUCT_NAT_DECISION
- _INCLUDE_STRUCT_NAT_KV
- // TODO
- // define and implement the NAT table
- BPF_TABLE("extern", struct ct_k, struct ct_v, connections, 10240);
- BPF_TABLE("extern", int, struct packetHeaders, packet, 1);
- // TODO Study the possibility to use array intead of hash
- // for code porting form pbforwarder, and for simplicity
- // we choose to use hash maps
- #if _INGRESS_LOGIC
- BPF_TABLE("hash", uint32_t, struct nat_v, natrules_DIRECTION, 64);
- #endif
- #if _EGRESS_LOGIC
- BPF_TABLE("hash", uint32_t, struct nat_v, natrules_DIRECTION, 64);
- #endif
- #undef HARDCODED_NAT_RULE
- // #define HARDCODED_NAT_RULE
- // This is the percpu array containing the NAT decision. Subsequent NAT mdoules just lookup this value
- BPF_TABLE("extern", int, struct nat_decision, natDecision, 1);
- static int handle_rx(struct CTXTYPE *ctx, struct pkt_metadata *md) {
- // NAT parts
- // Part 1: Nat.cpp, Iptables_Nat_dp.h: lookup in the CT table
- // Part 2: NatLookup.cpp, Iptables_NatLookup_dp.h: lookup in the NAT table
- // Part 3: NatAction.cpp, Iptables_NatAction_dp.h: apply NAT
- // ---------------------------
- // NAT part 2: lookup the NAT table to check if any rule applies to the packet
- // In part 1, a lookup in the CT table is performed
- // We get here in 2 cases
- // 1) the CT table does not have an entry for this packet
- // decision->entryPresent = 0
- // 2) the CT table contains an entry for this packet with trans_type UNDEF_NAT
- // decision->entryPresent = 1
- // decision->updateEntry = 1
- // entryPresent & updateEntry are managed by first module.
- // Either way we have to lookup the nat rule table: the outcome can be SRC, DST
- // or NO_NAT. If the resulting trans_type is NO_NAT (no matching entry in the NAT table),
- // we have to go to part 3 anyway, because only part 3 can update the CT table
- // In practice, this means we can ignore the decision here, because if we are here we
- // have to lookup, for sure. After the lookup we update decision->newIp, decision->newPort,
- // decision->match and go to part 3
- // This is only a lookup module, no change whatsoever is applied to the packet here.
- // The decision will be read by part 3, which will perform the necessary actions
- iovnet_log(ctx, LOG_TRACE, "[NAT RULE LOOKUP _DIRECTION] Received packet ");
- int k = 0;
- struct packetHeaders *pkt = packet.lookup(&k);
- if (pkt == NULL) {
- // Not possible
- return RX_DROP;
- }
- struct nat_decision *decision = natDecision.lookup(&k);
- if (decision == NULL) {
- // Not possible
- return RX_DROP;
- }
- iovnet_log(ctx, LOG_TRACE, "[NAT RULE LOOKUP _DIRECTION] Nr Rules: _RULES ");
- #ifdef HARDCODED_NAT_RULE
- #if _INGRESS_LOGIC
- // Testing with static mapping: ../../test/local_test6_iptables.sh
- if (pkt->l4proto == IPPROTO_TCP) {
- iovnet_log(ctx, LOG_TRACE, "[NAT RULE LOOKUP _DIRECTION] Packet is TCP");
- if (bpf_ntohs(pkt->dstPort) == 60123) {
- decision->match = DST;
- decision->newIp = pkt->dstIp;
- decision->newPort = bpf_htons(60321);
- iovnet_log(ctx, LOG_TRACE, "[NAT RULE LOOKUP _DIRECTION] TCP srcPort: %d, dstPort: %d", bpf_ntohs(pkt->srcPort), bpf_ntohs(pkt->dstPort));
- }
- else {
- // Until we make it work
- decision->match = NO_NAT;
- decision->entryPresent = 1;
- decision->updateEntry = 0;
- }
- } else {
- // Until we make it work
- decision->match = NO_NAT;
- decision->entryPresent = 1;
- decision->updateEntry = 0;
- }
- #endif
- #if _EGRESS_LOGIC
- iovnet_log(ctx, LOG_TRACE, "[NAT RULE LOOKUP _DIRECTION] Egress logic. No nat rule.");
- // Until we make it work
- decision->match = NO_NAT;
- decision->entryPresent = 1;
- decision->updateEntry = 0;
- #endif
- #endif
- #ifndef HARDCODED_NAT_RULE
- #define BITS_PER_WORD (sizeof(uint32_t) * 8)
- #define BIT_OFFSET(b) ((b) % BITS_PER_WORD)
- #define GET_BIT(word, n) (word & (1ULL << BIT_OFFSET(n)))
- // regular algorithm
- struct nat_v *nat_value = 0;
- #if _RULES == 0
- iovnet_log(ctx, LOG_DEBUG, "[NAT RULE LOOKUP _DIRECTION] No natting rules. ");
- // todo what to do?
- goto NOT_MATCHED;
- #elif _RULES == 1
- int key = 0;
- nat_value = natrules_DIRECTION.lookup(&key);
- if (nat_value == NULL){
- // No rule with this ID
- goto NOT_MATCHED;
- }
- #elif _RULES > 1
- #pragma unroll
- for (int i = 0; i < _RULES; i++) {
- int key = i;
- nat_value = natrules_DIRECTION.lookup(&key);
- if (nat_value == NULL){
- // No rule with this ID
- goto NOT_MATCHED;
- }
- #endif
- // TODO: improve, inject only needed field match
- /* Src IP Match */
- 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 );
- if (GET_BIT(nat_value->bitmask, 0)) {
- if (pkt->srcIp != nat_value->srcIp)
- goto NOT_MATCHED;
- }
- /* Dst IP Match */
- 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 );
- if (GET_BIT(nat_value->bitmask, 1)) {
- if (pkt->dstIp != nat_value->dstIp)
- goto NOT_MATCHED;
- }
- /* Src Port Match */
- 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 );
- if (GET_BIT(nat_value->bitmask, 2)) {
- if (pkt->srcPort != nat_value->srcPort)
- goto NOT_MATCHED;
- }
- /* Dst Port Match */
- 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 );
- if (GET_BIT(nat_value->bitmask, 3)) {
- if (pkt->dstPort != nat_value->dstPort)
- goto NOT_MATCHED;
- }
- /* L4 Proto Match */
- 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 );
- if (GET_BIT(nat_value->bitmask, 4)) {
- if (pkt->l4proto != nat_value->l4proto)
- goto NOT_MATCHED;
- }
- // /* TCP Flags Match */
- // if (GET_BIT(nat_value->bitmask, 5)) {
- // if (pkt->flags != nat_value->tcpFlags)
- // goto NOT_MATCHED;
- // }
- #if _INGRESS_LOGIC
- /* In Interface Match */
- 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 );
- if (GET_BIT(nat_value->bitmask, 6)) {
- if (md->in_port != nat_value->inIface)
- goto NOT_MATCHED;
- }
- #endif
- #if _EGRESS_LOGIC
- /* In Interface Match */
- 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 );
- if (GET_BIT(nat_value->bitmask, 7)) {
- if (md->in_port != nat_value->outIface)
- goto NOT_MATCHED;
- }
- #endif
- // RULE MATCHED
- decision->match = nat_value->type;
- decision->newIp = nat_value->newIp;
- // TODO in case of SNAT, newPort is not assigned. It should be provided by algorithm for
- // selecting first free port. This should be implemented in the following module.
- decision->newPort = nat_value->newPort;
- //TODO: Implement SNAT find first free port!
- // if rule == SNAT
- // newPort = findFirstFreePort();
- 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 );
- goto NEXT_PROGRAM;
- NOT_MATCHED:;
- #if _RULES > 1
- } // Close for
- #endif
- decision->match = NO_NAT;
- #endif
- NEXT_PROGRAM:;
- call_bpf_program(ctx, _NAT_ACTION);
- return RX_DROP;
- }
- )";
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement