static void print_state(unsigned int statemask) { const char *sep = ""; if (statemask & IPT_CONNTRACK_STATE_INVALID) { printf("%sINVALID", sep); sep = ","; } if (statemask & IPT_CONNTRACK_STATE_BIT(IP_CT_NEW)) { printf("%sNEW", sep); sep = ","; } if (statemask & IPT_CONNTRACK_STATE_BIT(IP_CT_RELATED)) { printf("%sRELATED", sep); sep = ","; } if (statemask & IPT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED)) { printf("%sESTABLISHED", sep); sep = ","; } if (statemask & IPT_CONNTRACK_STATE_UNTRACKED) { printf("%sUNTRACKED", sep); sep = ","; } if (statemask & IPT_CONNTRACK_STATE_SNAT) { printf("%sSNAT", sep); sep = ","; } if (statemask & IPT_CONNTRACK_STATE_DNAT) { printf("%sDNAT", sep); sep = ","; } printf(" "); }
/* * Put in -rule- the netfilter rule: * * -A POSTROUTING -o ntk_tunl+ -m conntrack * --ctstate NEW -j ntk_mark_chain * * -rule- has to be NTK_FORWARD_RULE_SZ-sized */ void ntk_forward_rule_init(char *rule) { struct ipt_entry *ee; struct ipt_entry_match *em; struct ipt_entry_target *et; struct ipt_conntrack_info *ici; memset(rule, 0, NTK_FORWARD_RULE_SZ); ee = (struct ipt_entry *) (rule); em = (struct ipt_entry_match *) (rule + IPT_ENTRY_SZ); ici = (struct ipt_conntrack_info *) (rule + OFFSET_MATCH_INFO); et = (struct ipt_entry_target *) (rule + OFFSET_TARGET); ee->next_offset = NTK_FORWARD_RULE_SZ; ee->target_offset = OFFSET_TARGET; snprintf(ee->ip.outiface, IFNAMSIZ, "%s+", NTK_TUNL_PREFIX); memset(ee->ip.outiface_mask, 0xFF, strlen(ee->ip.outiface) - 1); strcpy(em->u.user.name, MOD_CONNTRACK); em->u.match_size = MATCH_SZ; em->u.user.match_size = em->u.match_size; ici->flags = 1; ici->statemask |= IPT_CONNTRACK_STATE_BIT(IP_CT_NEW); et->u.target_size = IPT_ENTRY_TARGET_SZ + 4; et->u.user.target_size = et->u.target_size; strcpy(et->u.user.name, NTK_MARK_CHAIN); }
static int parse_state(const char *state, size_t strlen, struct ipt_conntrack_info *sinfo) { if (strncasecmp(state, "INVALID", strlen) == 0) sinfo->statemask |= IPT_CONNTRACK_STATE_INVALID; else if (strncasecmp(state, "NEW", strlen) == 0) sinfo->statemask |= IPT_CONNTRACK_STATE_BIT(IP_CT_NEW); else if (strncasecmp(state, "ESTABLISHED", strlen) == 0) sinfo->statemask |= IPT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED); else if (strncasecmp(state, "RELATED", strlen) == 0) sinfo->statemask |= IPT_CONNTRACK_STATE_BIT(IP_CT_RELATED); else if (strncasecmp(state, "UNTRACKED", strlen) == 0) sinfo->statemask |= IPT_CONNTRACK_STATE_UNTRACKED; else if (strncasecmp(state, "SNAT", strlen) == 0) sinfo->statemask |= IPT_CONNTRACK_STATE_SNAT; else if (strncasecmp(state, "DNAT", strlen) == 0) sinfo->statemask |= IPT_CONNTRACK_STATE_DNAT; else return 0; return 1; }
/* * Put in -rule- the netfilter rule: * * -A OUTPUT -o ntk_tunl+ -m conntrack \ * --ctstate RELATED,ESTABLISHED -j CONNMARK \ * --restore-mark * * -rule- has to be RESTORE_OUTPUT_RULE_SZ-sized */ void restore_output_rule_init(char *rule) { struct ipt_entry *ee; struct ipt_entry_match *em; struct ipt_entry_target *et; struct ipt_conntrack_info *ici; struct ipt_connmark_target_info *icmi; memset(rule, 0, RESTORE_OUTPUT_RULE_SZ); ee = (struct ipt_entry *) (rule); em = (struct ipt_entry_match *) (rule + OFFSET_MATCH); ici = (struct ipt_conntrack_info *) (rule + OFFSET_MATCH_INFO); et = (struct ipt_entry_target *) (rule + OFFSET_TARGET); icmi = (struct ipt_connmark_target_info *) (rule + OFFSET_TARGET_INFO); ee->next_offset = RESTORE_OUTPUT_RULE_SZ; ee->target_offset = OFFSET_TARGET; snprintf(ee->ip.outiface, IFNAMSIZ, "%s+", NTK_TUNL_PREFIX); memset(ee->ip.outiface_mask, 0xFF, strlen(ee->ip.outiface) - 1); strcpy(em->u.user.name, MOD_CONNTRACK); em->u.match_size = MATCH_SZ;; em->u.user.match_size = em->u.match_size; et->u.target_size = TARGET_SZ; et->u.user.target_size = et->u.target_size; strcpy(et->u.user.name, MOD_CONNMARK); ici->flags = 1; ici->statemask |= IPT_CONNTRACK_STATE_BIT(IP_CT_RELATED); ici->statemask |= IPT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED); icmi->mode = IPT_CONNMARK_RESTORE; icmi->mask = 0xffffffffUL; }
static int match(const struct sk_buff *skb, const struct net_device *in, const struct net_device *out, const void *matchinfo, int offset, const void *hdr, u_int16_t datalen, int *hotdrop) { const struct ipt_conntrack_info *sinfo = matchinfo; struct ip_conntrack *ct; enum ip_conntrack_info ctinfo; unsigned int statebit; ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo); #define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg)) if (ct) statebit = IPT_CONNTRACK_STATE_BIT(ctinfo); else statebit = IPT_CONNTRACK_STATE_INVALID; if(sinfo->flags & IPT_CONNTRACK_STATE) { if (ct) { if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip != ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip) statebit |= IPT_CONNTRACK_STATE_SNAT; if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip != ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip) statebit |= IPT_CONNTRACK_STATE_DNAT; } if (FWINV((statebit & sinfo->statemask) == 0, IPT_CONNTRACK_STATE)) return 0; } if(sinfo->flags & IPT_CONNTRACK_PROTO) { if (!ct || FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum, IPT_CONNTRACK_PROTO)) return 0; } if(sinfo->flags & IPT_CONNTRACK_ORIGSRC) { if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip&sinfo->sipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip, IPT_CONNTRACK_ORIGSRC)) return 0; } if(sinfo->flags & IPT_CONNTRACK_ORIGDST) { if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip&sinfo->dipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip, IPT_CONNTRACK_ORIGDST)) return 0; } if(sinfo->flags & IPT_CONNTRACK_REPLSRC) { if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip&sinfo->sipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].src.ip, IPT_CONNTRACK_REPLSRC)) return 0; } if(sinfo->flags & IPT_CONNTRACK_REPLDST) { if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip&sinfo->dipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].dst.ip, IPT_CONNTRACK_REPLDST)) return 0; } if(sinfo->flags & IPT_CONNTRACK_STATUS) { if (!ct || FWINV((ct->status & sinfo->statusmask) == 0, IPT_CONNTRACK_STATUS)) return 0; } if(sinfo->flags & IPT_CONNTRACK_EXPIRES) { unsigned long expires; if(!ct) return 0; expires = timer_pending(&ct->timeout) ? (ct->timeout.expires - jiffies)/HZ : 0; if (FWINV(!(expires >= sinfo->expires_min && expires <= sinfo->expires_max), IPT_CONNTRACK_EXPIRES)) return 0; } return 1; }