static void synproxy_send_server_syn(struct net *net, const struct sk_buff *skb, const struct tcphdr *th, const struct synproxy_options *opts, u32 recv_seq) { struct synproxy_net *snet = synproxy_pernet(net); struct sk_buff *nskb; struct iphdr *iph, *niph; struct tcphdr *nth; unsigned int tcp_hdr_size; iph = ip_hdr(skb); tcp_hdr_size = sizeof(*nth) + synproxy_options_size(opts); nskb = alloc_skb(sizeof(*niph) + tcp_hdr_size + MAX_TCP_HEADER, GFP_ATOMIC); if (nskb == NULL) return; skb_reserve(nskb, MAX_TCP_HEADER); niph = synproxy_build_ip(net, nskb, iph->saddr, iph->daddr); skb_reset_transport_header(nskb); nth = (struct tcphdr *)skb_put(nskb, tcp_hdr_size); nth->source = th->source; nth->dest = th->dest; nth->seq = htonl(recv_seq - 1); /* ack_seq is used to relay our ISN to the synproxy hook to initialize * sequence number translation once a connection tracking entry exists. */ nth->ack_seq = htonl(ntohl(th->ack_seq) - 1); tcp_flag_word(nth) = TCP_FLAG_SYN; if (opts->options & XT_SYNPROXY_OPT_ECN) tcp_flag_word(nth) |= TCP_FLAG_ECE | TCP_FLAG_CWR; nth->doff = tcp_hdr_size / 4; nth->window = th->window; nth->check = 0; nth->urg_ptr = 0; synproxy_build_options(nth, opts); synproxy_send_tcp(net, skb, nskb, &snet->tmpl->ct_general, IP_CT_NEW, niph, nth, tcp_hdr_size); }
static void synproxy_send_client_synack(struct net *net, const struct sk_buff *skb, const struct tcphdr *th, const struct synproxy_options *opts) { struct sk_buff *nskb; struct iphdr *iph, *niph; struct tcphdr *nth; unsigned int tcp_hdr_size; u16 mss = opts->mss; iph = ip_hdr(skb); tcp_hdr_size = sizeof(*nth) + synproxy_options_size(opts); nskb = alloc_skb(sizeof(*niph) + tcp_hdr_size + MAX_TCP_HEADER, GFP_ATOMIC); if (nskb == NULL) return; skb_reserve(nskb, MAX_TCP_HEADER); niph = synproxy_build_ip(net, nskb, iph->daddr, iph->saddr); skb_reset_transport_header(nskb); nth = (struct tcphdr *)skb_put(nskb, tcp_hdr_size); nth->source = th->dest; nth->dest = th->source; nth->seq = htonl(__cookie_v4_init_sequence(iph, th, &mss)); nth->ack_seq = htonl(ntohl(th->seq) + 1); tcp_flag_word(nth) = TCP_FLAG_SYN | TCP_FLAG_ACK; if (opts->options & XT_SYNPROXY_OPT_ECN) tcp_flag_word(nth) |= TCP_FLAG_ECE; nth->doff = tcp_hdr_size / 4; nth->window = 0; nth->check = 0; nth->urg_ptr = 0; synproxy_build_options(nth, opts); synproxy_send_tcp(net, skb, nskb, skb->nfct, IP_CT_ESTABLISHED_REPLY, niph, nth, tcp_hdr_size); }
static void synproxy_send_server_ack(const struct synproxy_net *snet, const struct ip_ct_tcp *state, const struct sk_buff *skb, const struct tcphdr *th, const struct synproxy_options *opts) { struct sk_buff *nskb; struct ipv6hdr *iph, *niph; struct tcphdr *nth; unsigned int tcp_hdr_size; iph = ipv6_hdr(skb); tcp_hdr_size = sizeof(*nth) + synproxy_options_size(opts); nskb = alloc_skb(sizeof(*niph) + tcp_hdr_size + MAX_TCP_HEADER, GFP_ATOMIC); if (nskb == NULL) return; skb_reserve(nskb, MAX_TCP_HEADER); niph = synproxy_build_ip(nskb, &iph->daddr, &iph->saddr); skb_reset_transport_header(nskb); nth = (struct tcphdr *)skb_put(nskb, tcp_hdr_size); nth->source = th->dest; nth->dest = th->source; nth->seq = htonl(ntohl(th->ack_seq)); nth->ack_seq = htonl(ntohl(th->seq) + 1); tcp_flag_word(nth) = TCP_FLAG_ACK; nth->doff = tcp_hdr_size / 4; nth->window = htons(state->seen[IP_CT_DIR_ORIGINAL].td_maxwin); nth->check = 0; nth->urg_ptr = 0; synproxy_build_options(nth, opts); synproxy_send_tcp(skb, nskb, NULL, 0, niph, nth, tcp_hdr_size); }
static void synproxy_send_client_ack(const struct synproxy_net *snet, const struct sk_buff *skb, const struct tcphdr *th, const struct synproxy_options *opts) { struct sk_buff *nskb; struct iphdr *iph, *niph; struct tcphdr *nth; unsigned int tcp_hdr_size; iph = ip_hdr(skb); tcp_hdr_size = sizeof(*nth) + synproxy_options_size(opts); nskb = alloc_skb(sizeof(*niph) + tcp_hdr_size + MAX_TCP_HEADER, GFP_ATOMIC); if (nskb == NULL) return; skb_reserve(nskb, MAX_TCP_HEADER); niph = synproxy_build_ip(nskb, iph->saddr, iph->daddr); skb_reset_transport_header(nskb); nth = (struct tcphdr *)skb_put(nskb, tcp_hdr_size); nth->source = th->source; nth->dest = th->dest; nth->seq = htonl(ntohl(th->seq) + 1); nth->ack_seq = th->ack_seq; tcp_flag_word(nth) = TCP_FLAG_ACK; nth->doff = tcp_hdr_size / 4; nth->window = htons(ntohs(th->window) >> opts->wscale); nth->check = 0; nth->urg_ptr = 0; synproxy_build_options(nth, opts); synproxy_send_tcp(snet, skb, nskb, skb->nfct, IP_CT_ESTABLISHED_REPLY, niph, nth, tcp_hdr_size); }
static void __skb_flow_dissect_tcp(const struct sk_buff *skb, struct flow_dissector *flow_dissector, void *target_container, void *data, int thoff, int hlen) { struct flow_dissector_key_tcp *key_tcp; struct tcphdr *th, _th; if (!dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_TCP)) return; th = __skb_header_pointer(skb, thoff, sizeof(_th), data, hlen, &_th); if (!th) return; if (unlikely(__tcp_hdrlen(th) < sizeof(_th))) return; key_tcp = skb_flow_dissector_target(flow_dissector, FLOW_DISSECTOR_KEY_TCP, target_container); key_tcp->flags = (*(__be16 *) &tcp_flag_word(th) & htons(0x0FFF)); }
/* One level of recursion won't kill us */ static void dump_packet(const struct nf_loginfo *info, const struct sk_buff *skb, unsigned int ip6hoff, int recurse) { u_int8_t currenthdr; int fragment; struct ipv6hdr _ip6h; const struct ipv6hdr *ih; unsigned int ptr; unsigned int hdrlen = 0; unsigned int logflags; if (info->type == NF_LOG_TYPE_LOG) logflags = info->u.log.logflags; else logflags = NF_LOG_MASK; ih = skb_header_pointer(skb, ip6hoff, sizeof(_ip6h), &_ip6h); if (ih == NULL) { printk("TRUNCATED"); return; } /* Max length: 88 "SRC=0000.0000.0000.0000.0000.0000.0000.0000 DST=0000.0000.0000.0000.0000.0000.0000.0000 " */ printk("SRC=%pI6 DST=%pI6 ", &ih->saddr, &ih->daddr); /* Max length: 44 "LEN=65535 TC=255 HOPLIMIT=255 FLOWLBL=FFFFF " */ printk("LEN=%Zu TC=%u HOPLIMIT=%u FLOWLBL=%u ", ntohs(ih->payload_len) + sizeof(struct ipv6hdr), (ntohl(*(__be32 *)ih) & 0x0ff00000) >> 20, ih->hop_limit, (ntohl(*(__be32 *)ih) & 0x000fffff)); fragment = 0; ptr = ip6hoff + sizeof(struct ipv6hdr); currenthdr = ih->nexthdr; while (currenthdr != NEXTHDR_NONE && ip6t_ext_hdr(currenthdr)) { struct ipv6_opt_hdr _hdr; const struct ipv6_opt_hdr *hp; hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); if (hp == NULL) { printk("TRUNCATED"); return; } /* Max length: 48 "OPT (...) " */ if (logflags & IP6T_LOG_IPOPT) printk("OPT ( "); switch (currenthdr) { case IPPROTO_FRAGMENT: { struct frag_hdr _fhdr; const struct frag_hdr *fh; printk("FRAG:"); fh = skb_header_pointer(skb, ptr, sizeof(_fhdr), &_fhdr); if (fh == NULL) { printk("TRUNCATED "); return; } /* Max length: 6 "65535 " */ printk("%u ", ntohs(fh->frag_off) & 0xFFF8); /* Max length: 11 "INCOMPLETE " */ if (fh->frag_off & htons(0x0001)) printk("INCOMPLETE "); printk("ID:%08x ", ntohl(fh->identification)); if (ntohs(fh->frag_off) & 0xFFF8) fragment = 1; hdrlen = 8; break; } case IPPROTO_DSTOPTS: case IPPROTO_ROUTING: case IPPROTO_HOPOPTS: if (fragment) { if (logflags & IP6T_LOG_IPOPT) printk(")"); return; } hdrlen = ipv6_optlen(hp); break; /* Max Length */ case IPPROTO_AH: if (logflags & IP6T_LOG_IPOPT) { struct ip_auth_hdr _ahdr; const struct ip_auth_hdr *ah; /* Max length: 3 "AH " */ printk("AH "); if (fragment) { printk(")"); return; } ah = skb_header_pointer(skb, ptr, sizeof(_ahdr), &_ahdr); if (ah == NULL) { /* * Max length: 26 "INCOMPLETE [65535 * bytes] )" */ printk("INCOMPLETE [%u bytes] )", skb->len - ptr); return; } /* Length: 15 "SPI=0xF1234567 */ printk("SPI=0x%x ", ntohl(ah->spi)); } hdrlen = (hp->hdrlen+2)<<2; break; case IPPROTO_ESP: if (logflags & IP6T_LOG_IPOPT) { struct ip_esp_hdr _esph; const struct ip_esp_hdr *eh; /* Max length: 4 "ESP " */ printk("ESP "); if (fragment) { printk(")"); return; } /* * Max length: 26 "INCOMPLETE [65535 bytes] )" */ eh = skb_header_pointer(skb, ptr, sizeof(_esph), &_esph); if (eh == NULL) { printk("INCOMPLETE [%u bytes] )", skb->len - ptr); return; } /* Length: 16 "SPI=0xF1234567 )" */ printk("SPI=0x%x )", ntohl(eh->spi) ); } return; default: /* Max length: 20 "Unknown Ext Hdr 255" */ printk("Unknown Ext Hdr %u", currenthdr); return; } if (logflags & IP6T_LOG_IPOPT) printk(") "); currenthdr = hp->nexthdr; ptr += hdrlen; } switch (currenthdr) { case IPPROTO_TCP: { struct tcphdr _tcph; const struct tcphdr *th; /* Max length: 10 "PROTO=TCP " */ printk("PROTO=TCP "); if (fragment) break; /* Max length: 25 "INCOMPLETE [65535 bytes] " */ th = skb_header_pointer(skb, ptr, sizeof(_tcph), &_tcph); if (th == NULL) { printk("INCOMPLETE [%u bytes] ", skb->len - ptr); return; } /* Max length: 20 "SPT=65535 DPT=65535 " */ printk("SPT=%u DPT=%u ", ntohs(th->source), ntohs(th->dest)); /* Max length: 30 "SEQ=4294967295 ACK=4294967295 " */ if (logflags & IP6T_LOG_TCPSEQ) printk("SEQ=%u ACK=%u ", ntohl(th->seq), ntohl(th->ack_seq)); /* Max length: 13 "WINDOW=65535 " */ printk("WINDOW=%u ", ntohs(th->window)); /* Max length: 9 "RES=0x3C " */ printk("RES=0x%02x ", (u_int8_t)(ntohl(tcp_flag_word(th) & TCP_RESERVED_BITS) >> 22)); /* Max length: 32 "CWR ECE URG ACK PSH RST SYN FIN " */ if (th->cwr) printk("CWR "); if (th->ece) printk("ECE "); if (th->urg) printk("URG "); if (th->ack) printk("ACK "); if (th->psh) printk("PSH "); if (th->rst) printk("RST "); if (th->syn) printk("SYN "); if (th->fin) printk("FIN "); /* Max length: 11 "URGP=65535 " */ printk("URGP=%u ", ntohs(th->urg_ptr)); if ((logflags & IP6T_LOG_TCPOPT) && th->doff * 4 > sizeof(struct tcphdr)) { u_int8_t _opt[60 - sizeof(struct tcphdr)]; const u_int8_t *op; unsigned int i; unsigned int optsize = th->doff * 4 - sizeof(struct tcphdr); op = skb_header_pointer(skb, ptr + sizeof(struct tcphdr), optsize, _opt); if (op == NULL) { printk("OPT (TRUNCATED)"); return; } /* Max length: 127 "OPT (" 15*4*2chars ") " */ printk("OPT ("); for (i =0; i < optsize; i++) printk("%02X", op[i]); printk(") "); } break; } case IPPROTO_UDP: case IPPROTO_UDPLITE: { struct udphdr _udph; const struct udphdr *uh; if (currenthdr == IPPROTO_UDP) /* Max length: 10 "PROTO=UDP " */ printk("PROTO=UDP " ); else /* Max length: 14 "PROTO=UDPLITE " */ printk("PROTO=UDPLITE "); if (fragment) break; /* Max length: 25 "INCOMPLETE [65535 bytes] " */ uh = skb_header_pointer(skb, ptr, sizeof(_udph), &_udph); if (uh == NULL) { printk("INCOMPLETE [%u bytes] ", skb->len - ptr); return; } /* Max length: 20 "SPT=65535 DPT=65535 " */ printk("SPT=%u DPT=%u LEN=%u ", ntohs(uh->source), ntohs(uh->dest), ntohs(uh->len)); break; } case IPPROTO_ICMPV6: { struct icmp6hdr _icmp6h; const struct icmp6hdr *ic; /* Max length: 13 "PROTO=ICMPv6 " */ printk("PROTO=ICMPv6 "); if (fragment) break; /* Max length: 25 "INCOMPLETE [65535 bytes] " */ ic = skb_header_pointer(skb, ptr, sizeof(_icmp6h), &_icmp6h); if (ic == NULL) { printk("INCOMPLETE [%u bytes] ", skb->len - ptr); return; } /* Max length: 18 "TYPE=255 CODE=255 " */ printk("TYPE=%u CODE=%u ", ic->icmp6_type, ic->icmp6_code); switch (ic->icmp6_type) { case ICMPV6_ECHO_REQUEST: case ICMPV6_ECHO_REPLY: /* Max length: 19 "ID=65535 SEQ=65535 " */ printk("ID=%u SEQ=%u ", ntohs(ic->icmp6_identifier), ntohs(ic->icmp6_sequence)); break; case ICMPV6_MGM_QUERY: case ICMPV6_MGM_REPORT: case ICMPV6_MGM_REDUCTION: break; case ICMPV6_PARAMPROB: /* Max length: 17 "POINTER=ffffffff " */ printk("POINTER=%08x ", ntohl(ic->icmp6_pointer)); /* Fall through */ case ICMPV6_DEST_UNREACH: case ICMPV6_PKT_TOOBIG: case ICMPV6_TIME_EXCEED: /* Max length: 3+maxlen */ if (recurse) { printk("["); dump_packet(info, skb, ptr + sizeof(_icmp6h), 0); printk("] "); } /* Max length: 10 "MTU=65535 " */ if (ic->icmp6_type == ICMPV6_PKT_TOOBIG) printk("MTU=%u ", ntohl(ic->icmp6_mtu)); } break; } /* Max length: 10 "PROTO=255 " */ default: printk("PROTO=%u ", currenthdr); } /* Max length: 15 "UID=4294967295 " */ if ((logflags & IP6T_LOG_UID) && recurse && skb->sk) { read_lock_bh(&skb->sk->sk_callback_lock); if (skb->sk->sk_socket && skb->sk->sk_socket->file) printk("UID=%u GID=%u ", skb->sk->sk_socket->file->f_cred->fsuid, skb->sk->sk_socket->file->f_cred->fsgid); read_unlock_bh(&skb->sk->sk_callback_lock); } /* Max length: 16 "MARK=0xFFFFFFFF " */ if (!recurse && skb->mark) printk("MARK=0x%x ", skb->mark); }
static int tcp_in_window(struct ip_ct_tcp *state, enum ip_conntrack_dir dir, unsigned int index, const struct sk_buff *skb, unsigned int dataoff, struct tcphdr *tcph, int pf) { struct ip_ct_tcp_state *sender = &state->seen[dir]; struct ip_ct_tcp_state *receiver = &state->seen[!dir]; __u32 seq, ack, sack, end, win; #if defined (CONFIG_RA_NAT_NONE) __u32 swin; #endif int res; /* * Get the required data from the packet. */ seq = ntohl(tcph->seq); ack = sack = ntohl(tcph->ack_seq); win = ntohs(tcph->window); end = segment_seq_plus_len(seq, skb->len, dataoff, tcph); if (receiver->flags & IP_CT_TCP_FLAG_SACK_PERM) tcp_sack(skb, dataoff, tcph, &sack); DEBUGP("tcp_in_window: START\n"); DEBUGP("tcp_in_window: src=%u.%u.%u.%u:%hu dst=%u.%u.%u.%u:%hu " "seq=%u ack=%u sack=%u win=%u end=%u\n", NIPQUAD(iph->saddr), ntohs(tcph->source), NIPQUAD(iph->daddr), ntohs(tcph->dest), seq, ack, sack, win, end); DEBUGP("tcp_in_window: sender end=%u maxend=%u maxwin=%u scale=%i " "receiver end=%u maxend=%u maxwin=%u scale=%i\n", sender->td_end, sender->td_maxend, sender->td_maxwin, sender->td_scale, receiver->td_end, receiver->td_maxend, receiver->td_maxwin, receiver->td_scale); if (sender->td_end == 0) { /* * Initialize sender data. */ if (tcph->syn && tcph->ack) { /* * Outgoing SYN-ACK in reply to a SYN. */ sender->td_end = sender->td_maxend = end; sender->td_maxwin = (win == 0 ? 1 : win); tcp_options(skb, dataoff, tcph, sender); /* * RFC 1323: * Both sides must send the Window Scale option * to enable window scaling in either direction. */ if (!(sender->flags & IP_CT_TCP_FLAG_WINDOW_SCALE && receiver->flags & IP_CT_TCP_FLAG_WINDOW_SCALE)) sender->td_scale = receiver->td_scale = 0; } else { /* * We are in the middle of a connection, * its history is lost for us. * Let's try to use the data from the packet. */ sender->td_end = end; sender->td_maxwin = (win == 0 ? 1 : win); sender->td_maxend = end + sender->td_maxwin; } } else if (((state->state == TCP_CONNTRACK_SYN_SENT && dir == IP_CT_DIR_ORIGINAL) || (state->state == TCP_CONNTRACK_SYN_RECV && dir == IP_CT_DIR_REPLY)) && after(end, sender->td_end)) { /* * RFC 793: "if a TCP is reinitialized ... then it need * not wait at all; it must only be sure to use sequence * numbers larger than those recently used." */ sender->td_end = sender->td_maxend = end; sender->td_maxwin = (win == 0 ? 1 : win); tcp_options(skb, dataoff, tcph, sender); } if (!(tcph->ack)) { /* * If there is no ACK, just pretend it was set and OK. */ ack = sack = receiver->td_end; } else if (((tcp_flag_word(tcph) & (TCP_FLAG_ACK|TCP_FLAG_RST)) == (TCP_FLAG_ACK|TCP_FLAG_RST)) && (ack == 0)) { /* * Broken TCP stacks, that set ACK in RST packets as well * with zero ack value. */ ack = sack = receiver->td_end; } if (seq == end && (!tcph->rst || (seq == 0 && state->state == TCP_CONNTRACK_SYN_SENT))) /* * Packets contains no data: we assume it is valid * and check the ack value only. * However RST segments are always validated by their * SEQ number, except when seq == 0 (reset sent answering * SYN. */ seq = end = sender->td_end; DEBUGP("tcp_in_window: src=%u.%u.%u.%u:%hu dst=%u.%u.%u.%u:%hu " "seq=%u ack=%u sack =%u win=%u end=%u\n", NIPQUAD(iph->saddr), ntohs(tcph->source), NIPQUAD(iph->daddr), ntohs(tcph->dest), seq, ack, sack, win, end); DEBUGP("tcp_in_window: sender end=%u maxend=%u maxwin=%u scale=%i " "receiver end=%u maxend=%u maxwin=%u scale=%i\n", sender->td_end, sender->td_maxend, sender->td_maxwin, sender->td_scale, receiver->td_end, receiver->td_maxend, receiver->td_maxwin, receiver->td_scale); DEBUGP("tcp_in_window: I=%i II=%i III=%i IV=%i\n", before(seq, sender->td_maxend + 1), after(end, sender->td_end - receiver->td_maxwin - 1), before(sack, receiver->td_end + 1), after(ack, receiver->td_end - MAXACKWINDOW(sender))); #if defined (CONFIG_RA_NAT_NONE) if (before(seq, sender->td_maxend + 1) && after(end, sender->td_end - receiver->td_maxwin - 1) && before(sack, receiver->td_end + 1) && after(ack, receiver->td_end - MAXACKWINDOW(sender))) { /* * Take into account window scaling (RFC 1323). */ if (!tcph->syn) win <<= sender->td_scale; /* * Update sender data. */ swin = win + (sack - ack); if (sender->td_maxwin < swin) sender->td_maxwin = swin; if (after(end, sender->td_end)) sender->td_end = end; /* * Update receiver data. */ if (after(end, sender->td_maxend)) receiver->td_maxwin += end - sender->td_maxend; if (after(sack + win, receiver->td_maxend - 1)) { receiver->td_maxend = sack + win; if (win == 0) receiver->td_maxend++; } /* * Check retransmissions. */ if (index == TCP_ACK_SET) { if (state->last_dir == dir && state->last_seq == seq && state->last_ack == ack && state->last_end == end && state->last_win == win) state->retrans++; else { state->last_dir = dir; state->last_seq = seq; state->last_ack = ack; state->last_end = end; state->last_win = win; state->retrans = 0; } } res = 1; } else { res = 0; if (sender->flags & IP_CT_TCP_FLAG_BE_LIBERAL || nf_ct_tcp_be_liberal) res = 1; if (!res && LOG_INVALID(IPPROTO_TCP)) nf_log_packet(pf, 0, skb, NULL, NULL, NULL, "nf_ct_tcp: %s ", before(seq, sender->td_maxend + 1) ? after(end, sender->td_end - receiver->td_maxwin - 1) ? before(sack, receiver->td_end + 1) ? after(ack, receiver->td_end - MAXACKWINDOW(sender)) ? "BUG" : "ACK is under the lower bound (possible overly delayed ACK)" : "ACK is over the upper bound (ACKed data not seen yet)" : "SEQ is under the lower bound (already ACKed data retransmitted)" : "SEQ is over the upper bound (over the window of the receiver)"); } #else res = 1; #endif DEBUGP("tcp_in_window: res=%i sender end=%u maxend=%u maxwin=%u " "receiver end=%u maxend=%u maxwin=%u\n", res, sender->td_end, sender->td_maxend, sender->td_maxwin, receiver->td_end, receiver->td_maxend, receiver->td_maxwin); return res; }
/* after ipt_filter */ static unsigned int ezp_nat_pre_hook(unsigned int hooknum, struct sk_buff *skb, const struct net_device *indev, const struct net_device *outdev, int (*okfn)(struct sk_buff *)) { struct nf_conn *ct; enum ip_conntrack_info ctinfo; int ret = NF_ACCEPT; enum ip_conntrack_dir dir; __u32 dnat_addr = 0, snat_addr = 0; int* nat_flag; struct dst_entry** dst_to_use = NULL; struct iphdr *iph = ip_hdr(skb); struct icmphdr *hdr = icmp_hdr(skb); struct tcphdr *tcph = tcp_hdr(skb); /* EZP: enum nf_nat_manip_type maniptype = HOOK2MANIP(hooknum); */ if(!ezp_nat_enable_flag){ return NF_ACCEPT; } ct = nf_ct_get(skb, &ctinfo); if (!ct) { if (iph->protocol == IPPROTO_ICMP && hdr->type == ICMP_REDIRECT) return NF_DROP; return NF_ACCEPT; } /* TCP or UDP. */ if ((iph->protocol != IPPROTO_TCP) && (iph->protocol != IPPROTO_UDP) ) { return NF_ACCEPT; } if ((iph->protocol == IPPROTO_TCP) && ((tcp_flag_word(tcph) & (TCP_FLAG_RST | TCP_FLAG_SYN)) == TCP_FLAG_SYN)) { return NF_ACCEPT; } /* Make sure it is confirmed. */ if (!nf_ct_is_confirmed(ct)) { return NF_ACCEPT; } /* We comment out this part since ((tcp_flag_word((*pskb)->h.th) == TCP_FLAG_SYN) || * 1. conntrack establishing is a 2 way process, but after routing, we have * established routing entry and address resolution table, so we don't * need to check ESTABLISH state. * 2. With establishing state, we need to go through forward state and * routing several times. It may occur that our holded entry may be * replaced. */ /* if ((ctinfo != IP_CT_ESTABLISHED) && (ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY)) { return NF_ACCEPT; } */ dir = CTINFO2DIR(ctinfo); if (dir == IP_CT_DIR_ORIGINAL) { if (!ct->orgdir_dst) { return NF_ACCEPT; } else { nat_flag = &ct->orgdir_rid; if (!(*nat_flag & ((1 << IP_NAT_MANIP_DST) | (1 << IP_NAT_MANIP_SRC) | (1 << EZP_IP_LOCAL_IN)))) { return NF_ACCEPT; } /* Check only in forward case and ignore input case */ if (!(*nat_flag & (1 << EZP_IP_LOCAL_IN))) { if ((!ct->orgdir_dst->hh) && (!ct->orgdir_dst->neighbour)) { printk("%s:orig dst and neighbour null dir\n",__FUNCTION__); return NF_ACCEPT; } } if (skb->dst) { /* skb might has its own dst already. * e.g. output to local input */ dst_release(skb->dst); } skb->protocol = htons(ETH_P_IP); skb->dst = ct->orgdir_dst; /* XXX: */ skb->dev = ct->orgdir_dst->dev; /* skb uses this dst_entry */ dst_use(skb->dst, jiffies); dst_to_use = &ct->orgdir_dst; } } else { /* IP_CT_DIR_REPLY */ if (!ct->replydir_dst) { return NF_ACCEPT; } else { nat_flag = &ct->replydir_rid; if (!(*nat_flag & ((1 << IP_NAT_MANIP_DST) | (1 << IP_NAT_MANIP_SRC) | (1 << EZP_IP_LOCAL_IN)))) { return NF_ACCEPT; } /* Check only in forward case and ignore input case */ if (!(*nat_flag & (1 << EZP_IP_LOCAL_IN))) { if ((!ct->replydir_dst->hh) && (!ct->replydir_dst->neighbour)) { printk("%s:reply dst and neighbour null\n",__FUNCTION__); return NF_ACCEPT; } } if (skb->dst) { /* skb might has its own dst already. */ /* e.g. output to local input */ dst_release(skb->dst); } skb->protocol = htons(ETH_P_IP); skb->dst = ct->replydir_dst; /* XXX: */ skb->dev = ct->replydir_dst->dev; /* skb uses this dst_entry */ dst_use(skb->dst, jiffies); dst_to_use = &ct->replydir_dst; } } /* After this point, every "return NF_ACCEPT" action need to release * holded dst entry. So we use "goto release_dst_and_return" to handle the * action commonly. */ /* EZP: if (!nf_nat_initialized(ct, maniptype)) { goto release_dst_and_return; } */ /* If we have helper, we need to go original path until conntrack * confirmed */ if(nfct_help(ct)){ goto release_dst_and_return; } if (dir == IP_CT_DIR_ORIGINAL) { (skb)->imq_flags = ct->ct_orig_imq_flags; } else{ (skb)->imq_flags = ct->ct_repl_imq_flags; } /* PRE_ROUTING NAT */ /* Assume DNAT conntrack is ready. */ if ((*nat_flag & (1 << IP_NAT_MANIP_DST))){ dnat_addr = iph->daddr; ret = nf_nat_packet(ct, ctinfo, NF_INET_PRE_ROUTING, skb); if (ret != NF_ACCEPT) { goto release_dst_and_return; } if (dnat_addr == iph->daddr) { *nat_flag &= ~(1 << IP_NAT_MANIP_DST); } } /* INPUT */ if ((*nat_flag & (1 << EZP_IP_LOCAL_IN))){ /* TODO: use ip_local_deliver_finish() and add ip_defrag(). */ /* XXX: Not sure this will hit or not. */ /* * Reassemble IP fragments. */ if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) { if (ip_defrag(skb, IP_DEFRAG_LOCAL_DELIVER)) { /* If return value is not 0, defrag error */ /* return 0; */ /* XXX: return NF_STOLEN? */ goto release_dst_and_return; } } /* For INPUT path, there is no need to check dst_mtu but defrag. if (skb->len > dst_mtu(&((struct rtable*)skb->dst)->u.dst)) { goto release_dst_and_return; }*/ if (ezp_nat_queue_enable_flag) { if ((skb)->imq_flags & IMQ_F_ENQUEUE) { struct nf_hook_ops *elem = nf_get_imq_ops(); /* With to apply IMQ, we have to check the IMQ flag, if the flag is * set, we have to enquene this skb and leave it to IMQ*/ if (elem != NULL) { nf_queue(skb, (struct list_head*)elem, AF_INET, NF_INET_POST_ROUTING, (struct net_device*)indev, (struct net_device*) ((struct rtable*)skb->dst)->u.dst.dev, ip_local_deliver_finish, NF_ACCEPT >> NF_VERDICT_BITS); return NF_STOLEN; } } } ret = ip_local_deliver_finish(skb); return NF_STOLEN; }
/* One level of recursion won't kill us */ static void dump_packet(const struct nf_loginfo *info, const struct sk_buff *skb, unsigned int iphoff) { struct iphdr _iph; const struct iphdr *ih; unsigned int logflags; if (info->type == NF_LOG_TYPE_LOG) logflags = info->u.log.logflags; else logflags = NF_LOG_MASK; ih = skb_header_pointer(skb, iphoff, sizeof(_iph), &_iph); if (ih == NULL) { printk("TRUNCATED"); return; } /* Important fields: * TOS, len, DF/MF, fragment offset, TTL, src, dst, options. */ /* Max length: 40 "SRC=255.255.255.255 DST=255.255.255.255 " */ printk("SRC=%pI4 DST=%pI4 ", &ih->saddr, &ih->daddr); /* Max length: 46 "LEN=65535 TOS=0xFF PREC=0xFF TTL=255 ID=65535 " */ printk("LEN=%u TOS=0x%02X PREC=0x%02X TTL=%u ID=%u ", ntohs(ih->tot_len), ih->tos & IPTOS_TOS_MASK, ih->tos & IPTOS_PREC_MASK, ih->ttl, ntohs(ih->id)); /* Max length: 6 "CE DF MF " */ if (ntohs(ih->frag_off) & IP_CE) printk("CE "); if (ntohs(ih->frag_off) & IP_DF) printk("DF "); if (ntohs(ih->frag_off) & IP_MF) printk("MF "); /* Max length: 11 "FRAG:65535 " */ if (ntohs(ih->frag_off) & IP_OFFSET) printk("FRAG:%u ", ntohs(ih->frag_off) & IP_OFFSET); if ((logflags & IPT_LOG_IPOPT) && ih->ihl * 4 > sizeof(struct iphdr)) { const unsigned char *op; unsigned char _opt[4 * 15 - sizeof(struct iphdr)]; unsigned int i, optsize; optsize = ih->ihl * 4 - sizeof(struct iphdr); op = skb_header_pointer(skb, iphoff+sizeof(_iph), optsize, _opt); if (op == NULL) { printk("TRUNCATED"); return; } /* Max length: 127 "OPT (" 15*4*2chars ") " */ printk("OPT ("); for (i = 0; i < optsize; i++) printk("%02X", op[i]); printk(") "); } switch (ih->protocol) { case IPPROTO_TCP: { struct tcphdr _tcph; const struct tcphdr *th; /* Max length: 10 "PROTO=TCP " */ printk("PROTO=TCP "); if (ntohs(ih->frag_off) & IP_OFFSET) break; /* Max length: 25 "INCOMPLETE [65535 bytes] " */ th = skb_header_pointer(skb, iphoff + ih->ihl * 4, sizeof(_tcph), &_tcph); if (th == NULL) { printk("INCOMPLETE [%u bytes] ", skb->len - iphoff - ih->ihl*4); break; } /* Max length: 20 "SPT=65535 DPT=65535 " */ printk("SPT=%u DPT=%u ", ntohs(th->source), ntohs(th->dest)); /* Max length: 30 "SEQ=4294967295 ACK=4294967295 " */ if (logflags & IPT_LOG_TCPSEQ) printk("SEQ=%u ACK=%u ", ntohl(th->seq), ntohl(th->ack_seq)); /* Max length: 13 "WINDOW=65535 " */ printk("WINDOW=%u ", ntohs(th->window)); /* Max length: 9 "RES=0x3F " */ printk("RES=0x%02x ", (u8)(ntohl(tcp_flag_word(th) & TCP_RESERVED_BITS) >> 22)); /* Max length: 32 "CWR ECE URG ACK PSH RST SYN FIN " */ if (th->cwr) printk("CWR "); if (th->ece) printk("ECE "); if (th->urg) printk("URG "); if (th->ack) printk("ACK "); if (th->psh) printk("PSH "); if (th->rst) printk("RST "); if (th->syn) printk("SYN "); if (th->fin) printk("FIN "); /* Max length: 11 "URGP=65535 " */ printk("URGP=%u ", ntohs(th->urg_ptr)); if ((logflags & IPT_LOG_TCPOPT) && th->doff * 4 > sizeof(struct tcphdr)) { unsigned char _opt[4 * 15 - sizeof(struct tcphdr)]; const unsigned char *op; unsigned int i, optsize; optsize = th->doff * 4 - sizeof(struct tcphdr); op = skb_header_pointer(skb, iphoff+ih->ihl*4+sizeof(_tcph), optsize, _opt); if (op == NULL) { printk("TRUNCATED"); return; } /* Max length: 127 "OPT (" 15*4*2chars ") " */ printk("OPT ("); for (i = 0; i < optsize; i++) printk("%02X", op[i]); printk(") "); } break; } case IPPROTO_UDP: case IPPROTO_UDPLITE: { struct udphdr _udph; const struct udphdr *uh; if (ih->protocol == IPPROTO_UDP) /* Max length: 10 "PROTO=UDP " */ printk("PROTO=UDP " ); else /* Max length: 14 "PROTO=UDPLITE " */ printk("PROTO=UDPLITE "); if (ntohs(ih->frag_off) & IP_OFFSET) break; /* Max length: 25 "INCOMPLETE [65535 bytes] " */ uh = skb_header_pointer(skb, iphoff+ih->ihl*4, sizeof(_udph), &_udph); if (uh == NULL) { printk("INCOMPLETE [%u bytes] ", skb->len - iphoff - ih->ihl*4); break; } /* Max length: 20 "SPT=65535 DPT=65535 " */ printk("SPT=%u DPT=%u LEN=%u ", ntohs(uh->source), ntohs(uh->dest), ntohs(uh->len)); break; } case IPPROTO_ICMP: { struct icmphdr _icmph; const struct icmphdr *ich; static const size_t required_len[NR_ICMP_TYPES+1] = { [ICMP_ECHOREPLY] = 4, [ICMP_DEST_UNREACH] = 8 + sizeof(struct iphdr), [ICMP_SOURCE_QUENCH] = 8 + sizeof(struct iphdr), [ICMP_REDIRECT] = 8 + sizeof(struct iphdr), [ICMP_ECHO] = 4, [ICMP_TIME_EXCEEDED] = 8 + sizeof(struct iphdr), [ICMP_PARAMETERPROB] = 8 + sizeof(struct iphdr), [ICMP_TIMESTAMP] = 20, [ICMP_TIMESTAMPREPLY] = 20, [ICMP_ADDRESS] = 12, [ICMP_ADDRESSREPLY] = 12 }; /* Max length: 11 "PROTO=ICMP " */ printk("PROTO=ICMP "); if (ntohs(ih->frag_off) & IP_OFFSET) break; /* Max length: 25 "INCOMPLETE [65535 bytes] " */ ich = skb_header_pointer(skb, iphoff + ih->ihl * 4, sizeof(_icmph), &_icmph); if (ich == NULL) { printk("INCOMPLETE [%u bytes] ", skb->len - iphoff - ih->ihl*4); break; } /* Max length: 18 "TYPE=255 CODE=255 " */ printk("TYPE=%u CODE=%u ", ich->type, ich->code); /* Max length: 25 "INCOMPLETE [65535 bytes] " */ if (ich->type <= NR_ICMP_TYPES && required_len[ich->type] && skb->len-iphoff-ih->ihl*4 < required_len[ich->type]) { printk("INCOMPLETE [%u bytes] ", skb->len - iphoff - ih->ihl*4); break; } switch (ich->type) { case ICMP_ECHOREPLY: case ICMP_ECHO: /* Max length: 19 "ID=65535 SEQ=65535 " */ printk("ID=%u SEQ=%u ", ntohs(ich->un.echo.id), ntohs(ich->un.echo.sequence)); break; case ICMP_PARAMETERPROB: /* Max length: 14 "PARAMETER=255 " */ printk("PARAMETER=%u ", ntohl(ich->un.gateway) >> 24); break; case ICMP_REDIRECT: /* Max length: 24 "GATEWAY=255.255.255.255 " */ printk("GATEWAY=%pI4 ", &ich->un.gateway); /* Fall through */ case ICMP_DEST_UNREACH: case ICMP_SOURCE_QUENCH: case ICMP_TIME_EXCEEDED: /* Max length: 3+maxlen */ if (!iphoff) { /* Only recurse once. */ printk("["); dump_packet(info, skb, iphoff + ih->ihl*4+sizeof(_icmph)); printk("] "); } /* Max length: 10 "MTU=65535 " */ if (ich->type == ICMP_DEST_UNREACH && ich->code == ICMP_FRAG_NEEDED) printk("MTU=%u ", ntohs(ich->un.frag.mtu)); } break; } /* Max Length */ case IPPROTO_AH: { struct ip_auth_hdr _ahdr; const struct ip_auth_hdr *ah; if (ntohs(ih->frag_off) & IP_OFFSET) break; /* Max length: 9 "PROTO=AH " */ printk("PROTO=AH "); /* Max length: 25 "INCOMPLETE [65535 bytes] " */ ah = skb_header_pointer(skb, iphoff+ih->ihl*4, sizeof(_ahdr), &_ahdr); if (ah == NULL) { printk("INCOMPLETE [%u bytes] ", skb->len - iphoff - ih->ihl*4); break; } /* Length: 15 "SPI=0xF1234567 " */ printk("SPI=0x%x ", ntohl(ah->spi)); break; } case IPPROTO_ESP: { struct ip_esp_hdr _esph; const struct ip_esp_hdr *eh; /* Max length: 10 "PROTO=ESP " */ printk("PROTO=ESP "); if (ntohs(ih->frag_off) & IP_OFFSET) break; /* Max length: 25 "INCOMPLETE [65535 bytes] " */ eh = skb_header_pointer(skb, iphoff+ih->ihl*4, sizeof(_esph), &_esph); if (eh == NULL) { printk("INCOMPLETE [%u bytes] ", skb->len - iphoff - ih->ihl*4); break; } /* Length: 15 "SPI=0xF1234567 " */ printk("SPI=0x%x ", ntohl(eh->spi)); break; } /* Max length: 10 "PROTO 255 " */ default: printk("PROTO=%u ", ih->protocol); } /* Max length: 15 "UID=4294967295 " */ if ((logflags & IPT_LOG_UID) && !iphoff && skb->sk) { read_lock_bh(&skb->sk->sk_callback_lock); if (skb->sk->sk_socket && skb->sk->sk_socket->file) printk("UID=%u GID=%u ", skb->sk->sk_socket->file->f_cred->fsuid, skb->sk->sk_socket->file->f_cred->fsgid); read_unlock_bh(&skb->sk->sk_callback_lock); } /* Max length: 16 "MARK=0xFFFFFFFF " */ if (!iphoff && skb->mark) printk("MARK=0x%x ", skb->mark); /* Proto Max log string length */ /* IP: 40+46+6+11+127 = 230 */ /* TCP: 10+max(25,20+30+13+9+32+11+127) = 252 */ /* UDP: 10+max(25,20) = 35 */ /* UDPLITE: 14+max(25,20) = 39 */ /* ICMP: 11+max(25, 18+25+max(19,14,24+3+n+10,3+n+10)) = 91+n */ /* ESP: 10+max(25)+15 = 50 */ /* AH: 9+max(25)+15 = 49 */ /* unknown: 10 */ /* (ICMP allows recursion one level deep) */ /* maxlen = IP + ICMP + IP + max(TCP,UDP,ICMP,unknown) */ /* maxlen = 230+ 91 + 230 + 252 = 803 */ }
/* One level of recursion won't kill us */ static void dump_packet(const struct ip6t_log_info *info, struct ipv6hdr *ipv6h, int recurse) { u_int8_t currenthdr = ipv6h->nexthdr; u_int8_t *hdrptr; int fragment; /* Max length: 88 "SRC=0000.0000.0000.0000.0000.0000.0000.0000 DST=0000.0000.0000.0000.0000.0000.0000.0000" */ printk("SRC=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(ipv6h->saddr)); printk("DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(ipv6h->daddr)); /* Max length: 44 "LEN=65535 TC=255 HOPLIMIT=255 FLOWLBL=FFFFF " */ printk("LEN=%Zu TC=%u HOPLIMIT=%u FLOWLBL=%u ", ntohs(ipv6h->payload_len) + sizeof(struct ipv6hdr), (ntohl(*(u_int32_t *)ipv6h) & 0x0ff00000) >> 20, ipv6h->hop_limit, (ntohl(*(u_int32_t *)ipv6h) & 0x000fffff)); fragment = 0; hdrptr = (u_int8_t *)(ipv6h + 1); while (currenthdr != IPPROTO_NONE) { if ((currenthdr == IPPROTO_TCP) || (currenthdr == IPPROTO_UDP) || (currenthdr == IPPROTO_ICMPV6)) break; /* Max length: 48 "OPT (...) " */ printk("OPT ( "); switch (currenthdr) { case IPPROTO_FRAGMENT: { struct frag_hdr *fhdr = (struct frag_hdr *)hdrptr; /* Max length: 11 "FRAG:65535 " */ printk("FRAG:%u ", ntohs(fhdr->frag_off) & 0xFFF8); /* Max length: 11 "INCOMPLETE " */ if (fhdr->frag_off & htons(0x0001)) printk("INCOMPLETE "); printk("ID:%08x ", fhdr->identification); if (ntohs(fhdr->frag_off) & 0xFFF8) fragment = 1; break; } case IPPROTO_DSTOPTS: case IPPROTO_ROUTING: case IPPROTO_HOPOPTS: break; /* Max Length */ case IPPROTO_AH: case IPPROTO_ESP: if (info->logflags & IP6T_LOG_IPOPT) { struct esphdr *esph = (struct esphdr *)hdrptr; int esp = (currenthdr == IPPROTO_ESP); /* Max length: 4 "ESP " */ printk("%s ",esp ? "ESP" : "AH"); /* Length: 15 "SPI=0xF1234567 " */ printk("SPI=0x%x ", ntohl(esph->spi) ); break; } default: break; } printk(") "); currenthdr = ip6_nexthdr(currenthdr, &hdrptr); } switch (currenthdr) { case IPPROTO_TCP: { struct tcphdr *tcph = (struct tcphdr *)hdrptr; /* Max length: 10 "PROTO=TCP " */ printk("PROTO=TCP "); if (fragment) break; /* Max length: 20 "SPT=65535 DPT=65535 " */ printk("SPT=%u DPT=%u ", ntohs(tcph->source), ntohs(tcph->dest)); /* Max length: 30 "SEQ=4294967295 ACK=4294967295 " */ if (info->logflags & IP6T_LOG_TCPSEQ) printk("SEQ=%u ACK=%u ", ntohl(tcph->seq), ntohl(tcph->ack_seq)); /* Max length: 13 "WINDOW=65535 " */ printk("WINDOW=%u ", ntohs(tcph->window)); /* Max length: 9 "RES=0x3F " */ printk("RES=0x%02x ", (u_int8_t)(ntohl(tcp_flag_word(tcph) & TCP_RESERVED_BITS) >> 22)); /* Max length: 32 "CWR ECE URG ACK PSH RST SYN FIN " */ if (tcph->cwr) printk("CWR "); if (tcph->ece) printk("ECE "); if (tcph->urg) printk("URG "); if (tcph->ack) printk("ACK "); if (tcph->psh) printk("PSH "); if (tcph->rst) printk("RST "); if (tcph->syn) printk("SYN "); if (tcph->fin) printk("FIN "); /* Max length: 11 "URGP=65535 " */ printk("URGP=%u ", ntohs(tcph->urg_ptr)); if ((info->logflags & IP6T_LOG_TCPOPT) && tcph->doff * 4 != sizeof(struct tcphdr)) { unsigned int i; /* Max length: 127 "OPT (" 15*4*2chars ") " */ printk("OPT ("); for (i =sizeof(struct tcphdr); i < tcph->doff * 4; i++) printk("%02X", ((u_int8_t *)tcph)[i]); printk(") "); } break; } case IPPROTO_UDP: { struct udphdr *udph = (struct udphdr *)hdrptr; /* Max length: 10 "PROTO=UDP " */ printk("PROTO=UDP "); if (fragment) break; /* Max length: 20 "SPT=65535 DPT=65535 " */ printk("SPT=%u DPT=%u LEN=%u ", ntohs(udph->source), ntohs(udph->dest), ntohs(udph->len)); break; } case IPPROTO_ICMPV6: { struct icmp6hdr *icmp6h = (struct icmp6hdr *)hdrptr; /* Max length: 13 "PROTO=ICMPv6 " */ printk("PROTO=ICMPv6 "); if (fragment) break; /* Max length: 18 "TYPE=255 CODE=255 " */ printk("TYPE=%u CODE=%u ", icmp6h->icmp6_type, icmp6h->icmp6_code); switch (icmp6h->icmp6_type) { case ICMPV6_ECHO_REQUEST: case ICMPV6_ECHO_REPLY: /* Max length: 19 "ID=65535 SEQ=65535 " */ printk("ID=%u SEQ=%u ", ntohs(icmp6h->icmp6_identifier), ntohs(icmp6h->icmp6_sequence)); break; case ICMPV6_MGM_QUERY: case ICMPV6_MGM_REPORT: case ICMPV6_MGM_REDUCTION: break; case ICMPV6_PARAMPROB: /* Max length: 17 "POINTER=ffffffff " */ printk("POINTER=%08x ", ntohl(icmp6h->icmp6_pointer)); /* Fall through */ case ICMPV6_DEST_UNREACH: case ICMPV6_PKT_TOOBIG: case ICMPV6_TIME_EXCEED: /* Max length: 3+maxlen */ if (recurse) { printk("["); dump_packet(info, (struct ipv6hdr *)(icmp6h + 1), 0); printk("] "); } /* Max length: 10 "MTU=65535 " */ if (icmp6h->icmp6_type == ICMPV6_PKT_TOOBIG) printk("MTU=%u ", ntohl(icmp6h->icmp6_mtu)); } break; } /* Max length: 10 "PROTO=255 " */ default: printk("PROTO=%u ", currenthdr); } }
static inline bool tflg_synack(const struct tcphdr *th) { return (tcp_flag_word(th) & TCP_FLAGS_ALL4) == (TCP_FLAG_SYN | TCP_FLAG_ACK); }
static inline bool tflg_syn(const struct tcphdr *th) { return (tcp_flag_word(th) & TCP_FLAGS_ALL4) == TCP_FLAG_SYN; }
static inline bool tflg_rst(const struct tcphdr *th) { return (tcp_flag_word(th) & TCP_FLAGS_ALL3) == TCP_FLAG_RST; }
static inline bool tflg_ack6(const struct tcphdr *th) { return (tcp_flag_word(th) & TCP_FLAGS_ALL6) == TCP_FLAG_ACK; }
static bool tcp_in_window(const struct nf_conn *ct, struct ip_ct_tcp *state, enum ip_conntrack_dir dir, unsigned int index, const struct sk_buff *skb, unsigned int dataoff, const struct tcphdr *tcph, u_int8_t pf) { struct net *net = nf_ct_net(ct); struct ip_ct_tcp_state *sender = &state->seen[dir]; struct ip_ct_tcp_state *receiver = &state->seen[!dir]; const struct nf_conntrack_tuple *tuple = &ct->tuplehash[dir].tuple; __u32 seq, ack, sack, end, win, swin; s16 receiver_offset; bool res; seq = ntohl(tcph->seq); ack = sack = ntohl(tcph->ack_seq); win = ntohs(tcph->window); end = segment_seq_plus_len(seq, skb->len, dataoff, tcph); if (receiver->flags & IP_CT_TCP_FLAG_SACK_PERM) tcp_sack(skb, dataoff, tcph, &sack); receiver_offset = NAT_OFFSET(pf, ct, !dir, ack - 1); ack -= receiver_offset; sack -= receiver_offset; pr_debug("tcp_in_window: START\n"); pr_debug("tcp_in_window: "); nf_ct_dump_tuple(tuple); pr_debug("seq=%u ack=%u+(%d) sack=%u+(%d) win=%u end=%u\n", seq, ack, receiver_offset, sack, receiver_offset, win, end); pr_debug("tcp_in_window: sender end=%u maxend=%u maxwin=%u scale=%i " "receiver end=%u maxend=%u maxwin=%u scale=%i\n", sender->td_end, sender->td_maxend, sender->td_maxwin, sender->td_scale, receiver->td_end, receiver->td_maxend, receiver->td_maxwin, receiver->td_scale); if (sender->td_maxwin == 0) { if (tcph->syn) { sender->td_end = sender->td_maxend = end; sender->td_maxwin = (win == 0 ? 1 : win); tcp_options(skb, dataoff, tcph, sender); if (!(sender->flags & IP_CT_TCP_FLAG_WINDOW_SCALE && receiver->flags & IP_CT_TCP_FLAG_WINDOW_SCALE)) sender->td_scale = receiver->td_scale = 0; if (!tcph->ack) return true; } else { sender->td_end = end; swin = win << sender->td_scale; sender->td_maxwin = (swin == 0 ? 1 : swin); sender->td_maxend = end + sender->td_maxwin; if (receiver->td_maxwin == 0) receiver->td_end = receiver->td_maxend = sack; } } else if (((state->state == TCP_CONNTRACK_SYN_SENT && dir == IP_CT_DIR_ORIGINAL) || (state->state == TCP_CONNTRACK_SYN_RECV && dir == IP_CT_DIR_REPLY)) && after(end, sender->td_end)) { sender->td_end = sender->td_maxend = end; sender->td_maxwin = (win == 0 ? 1 : win); tcp_options(skb, dataoff, tcph, sender); } if (!(tcph->ack)) { ack = sack = receiver->td_end; } else if (((tcp_flag_word(tcph) & (TCP_FLAG_ACK|TCP_FLAG_RST)) == (TCP_FLAG_ACK|TCP_FLAG_RST)) && (ack == 0)) { ack = sack = receiver->td_end; } if (seq == end && (!tcph->rst || (seq == 0 && state->state == TCP_CONNTRACK_SYN_SENT))) seq = end = sender->td_end; pr_debug("tcp_in_window: "); nf_ct_dump_tuple(tuple); pr_debug("seq=%u ack=%u+(%d) sack=%u+(%d) win=%u end=%u\n", seq, ack, receiver_offset, sack, receiver_offset, win, end); pr_debug("tcp_in_window: sender end=%u maxend=%u maxwin=%u scale=%i " "receiver end=%u maxend=%u maxwin=%u scale=%i\n", sender->td_end, sender->td_maxend, sender->td_maxwin, sender->td_scale, receiver->td_end, receiver->td_maxend, receiver->td_maxwin, receiver->td_scale); pr_debug("tcp_in_window: I=%i II=%i III=%i IV=%i\n", before(seq, sender->td_maxend + 1), after(end, sender->td_end - receiver->td_maxwin - 1), before(sack, receiver->td_end + 1), after(sack, receiver->td_end - MAXACKWINDOW(sender) - 1)); if (before(seq, sender->td_maxend + 1) && after(end, sender->td_end - receiver->td_maxwin - 1) && before(sack, receiver->td_end + 1) && after(sack, receiver->td_end - MAXACKWINDOW(sender) - 1)) { if (!tcph->syn) win <<= sender->td_scale; swin = win + (sack - ack); if (sender->td_maxwin < swin) sender->td_maxwin = swin; if (after(end, sender->td_end)) { sender->td_end = end; sender->flags |= IP_CT_TCP_FLAG_DATA_UNACKNOWLEDGED; } if (tcph->ack) { if (!(sender->flags & IP_CT_TCP_FLAG_MAXACK_SET)) { sender->td_maxack = ack; sender->flags |= IP_CT_TCP_FLAG_MAXACK_SET; } else if (after(ack, sender->td_maxack)) sender->td_maxack = ack; } if (receiver->td_maxwin != 0 && after(end, sender->td_maxend)) receiver->td_maxwin += end - sender->td_maxend; if (after(sack + win, receiver->td_maxend - 1)) { receiver->td_maxend = sack + win; if (win == 0) receiver->td_maxend++; } if (ack == receiver->td_end) receiver->flags &= ~IP_CT_TCP_FLAG_DATA_UNACKNOWLEDGED; if (index == TCP_ACK_SET) { if (state->last_dir == dir && state->last_seq == seq && state->last_ack == ack && state->last_end == end && state->last_win == win) state->retrans++; else { state->last_dir = dir; state->last_seq = seq; state->last_ack = ack; state->last_end = end; state->last_win = win; state->retrans = 0; } } res = true; } else { res = false; if (sender->flags & IP_CT_TCP_FLAG_BE_LIBERAL || nf_ct_tcp_be_liberal) res = true; if (!res && LOG_INVALID(net, IPPROTO_TCP)) nf_log_packet(pf, 0, skb, NULL, NULL, NULL, "nf_ct_tcp: %s ", before(seq, sender->td_maxend + 1) ? after(end, sender->td_end - receiver->td_maxwin - 1) ? before(sack, receiver->td_end + 1) ? after(sack, receiver->td_end - MAXACKWINDOW(sender) - 1) ? "BUG" : "ACK is under the lower bound (possible overly delayed ACK)" : "ACK is over the upper bound (ACKed data not seen yet)" : "SEQ is under the lower bound (already ACKed data retransmitted)" : "SEQ is over the upper bound (over the window of the receiver)"); } pr_debug("tcp_in_window: res=%u sender end=%u maxend=%u maxwin=%u " "receiver end=%u maxend=%u maxwin=%u\n", res, sender->td_end, sender->td_maxend, sender->td_maxwin, receiver->td_end, receiver->td_maxend, receiver->td_maxwin); return res; }
int nf_log_dump_tcp_header(struct nf_log_buf *m, const struct sk_buff *skb, u8 proto, int fragment, unsigned int offset, unsigned int logflags) { struct tcphdr _tcph; const struct tcphdr *th; /* Max length: 10 "PROTO=TCP " */ nf_log_buf_add(m, "PROTO=TCP "); if (fragment) return 0; /* Max length: 25 "INCOMPLETE [65535 bytes] " */ th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph); if (th == NULL) { nf_log_buf_add(m, "INCOMPLETE [%u bytes] ", skb->len - offset); return 1; } /* Max length: 20 "SPT=65535 DPT=65535 " */ nf_log_buf_add(m, "SPT=%u DPT=%u ", ntohs(th->source), ntohs(th->dest)); /* Max length: 30 "SEQ=4294967295 ACK=4294967295 " */ if (logflags & XT_LOG_TCPSEQ) { nf_log_buf_add(m, "SEQ=%u ACK=%u ", ntohl(th->seq), ntohl(th->ack_seq)); } /* Max length: 13 "WINDOW=65535 " */ nf_log_buf_add(m, "WINDOW=%u ", ntohs(th->window)); /* Max length: 9 "RES=0x3C " */ nf_log_buf_add(m, "RES=0x%02x ", (u_int8_t)(ntohl(tcp_flag_word(th) & TCP_RESERVED_BITS) >> 22)); /* Max length: 32 "CWR ECE URG ACK PSH RST SYN FIN " */ if (th->cwr) nf_log_buf_add(m, "CWR "); if (th->ece) nf_log_buf_add(m, "ECE "); if (th->urg) nf_log_buf_add(m, "URG "); if (th->ack) nf_log_buf_add(m, "ACK "); if (th->psh) nf_log_buf_add(m, "PSH "); if (th->rst) nf_log_buf_add(m, "RST "); if (th->syn) nf_log_buf_add(m, "SYN "); if (th->fin) nf_log_buf_add(m, "FIN "); /* Max length: 11 "URGP=65535 " */ nf_log_buf_add(m, "URGP=%u ", ntohs(th->urg_ptr)); if ((logflags & XT_LOG_TCPOPT) && th->doff*4 > sizeof(struct tcphdr)) { u_int8_t _opt[60 - sizeof(struct tcphdr)]; const u_int8_t *op; unsigned int i; unsigned int optsize = th->doff*4 - sizeof(struct tcphdr); op = skb_header_pointer(skb, offset + sizeof(struct tcphdr), optsize, _opt); if (op == NULL) { nf_log_buf_add(m, "OPT (TRUNCATED)"); return 1; } /* Max length: 127 "OPT (" 15*4*2chars ") " */ nf_log_buf_add(m, "OPT ("); for (i = 0; i < optsize; i++) nf_log_buf_add(m, "%02X", op[i]); nf_log_buf_add(m, ") "); } return 0; }
/* One level of recursion won't kill us */ static void dump_packet(const struct ipt_log_info *info, const struct sk_buff *skb, unsigned int iphoff) { struct iphdr iph; if (skb_copy_bits(skb, iphoff, &iph, sizeof(iph)) < 0) { printk("TRUNCATED"); return; } /* Important fields: * TOS, len, DF/MF, fragment offset, TTL, src, dst, options. */ /* Max length: 40 "SRC=255.255.255.255 DST=255.255.255.255 " */ printk("SRC=%u.%u.%u.%u DST=%u.%u.%u.%u ", NIPQUAD(iph.saddr), NIPQUAD(iph.daddr)); /* Max length: 46 "LEN=65535 TOS=0xFF PREC=0xFF TTL=255 ID=65535 " */ printk("LEN=%u TOS=0x%02X PREC=0x%02X TTL=%u ID=%u ", ntohs(iph.tot_len), iph.tos & IPTOS_TOS_MASK, iph.tos & IPTOS_PREC_MASK, iph.ttl, ntohs(iph.id)); /* Max length: 6 "CE DF MF " */ if (ntohs(iph.frag_off) & IP_CE) printk("CE "); if (ntohs(iph.frag_off) & IP_DF) printk("DF "); if (ntohs(iph.frag_off) & IP_MF) printk("MF "); /* Max length: 11 "FRAG:65535 " */ if (ntohs(iph.frag_off) & IP_OFFSET) printk("FRAG:%u ", ntohs(iph.frag_off) & IP_OFFSET); if ((info->logflags & IPT_LOG_IPOPT) && iph.ihl * 4 != sizeof(struct iphdr)) { unsigned char opt[4 * 15 - sizeof(struct iphdr)]; unsigned int i, optsize; optsize = iph.ihl * 4 - sizeof(struct iphdr); if (skb_copy_bits(skb, iphoff+sizeof(iph), opt, optsize) < 0) { printk("TRUNCATED"); return; } /* Max length: 127 "OPT (" 15*4*2chars ") " */ printk("OPT ("); for (i = 0; i < optsize; i++) printk("%02X", opt[i]); printk(") "); } switch (iph.protocol) { case IPPROTO_TCP: { struct tcphdr tcph; /* Max length: 10 "PROTO=TCP " */ printk("PROTO=TCP "); if (ntohs(iph.frag_off) & IP_OFFSET) break; /* Max length: 25 "INCOMPLETE [65535 bytes] " */ if (skb_copy_bits(skb, iphoff+iph.ihl*4, &tcph, sizeof(tcph)) < 0) { printk("INCOMPLETE [%u bytes] ", skb->len - iphoff - iph.ihl*4); break; } /* Max length: 20 "SPT=65535 DPT=65535 " */ printk("SPT=%u DPT=%u ", ntohs(tcph.source), ntohs(tcph.dest)); /* Max length: 30 "SEQ=4294967295 ACK=4294967295 " */ if (info->logflags & IPT_LOG_TCPSEQ) printk("SEQ=%u ACK=%u ", ntohl(tcph.seq), ntohl(tcph.ack_seq)); /* Max length: 13 "WINDOW=65535 " */ printk("WINDOW=%u ", ntohs(tcph.window)); /* Max length: 9 "RES=0x3F " */ printk("RES=0x%02x ", (u8)(ntohl(tcp_flag_word(&tcph) & TCP_RESERVED_BITS) >> 22)); /* Max length: 32 "CWR ECE URG ACK PSH RST SYN FIN " */ if (tcph.cwr) printk("CWR "); if (tcph.ece) printk("ECE "); if (tcph.urg) printk("URG "); if (tcph.ack) printk("ACK "); if (tcph.psh) printk("PSH "); if (tcph.rst) printk("RST "); if (tcph.syn) printk("SYN "); if (tcph.fin) printk("FIN "); /* Max length: 11 "URGP=65535 " */ printk("URGP=%u ", ntohs(tcph.urg_ptr)); if ((info->logflags & IPT_LOG_TCPOPT) && tcph.doff * 4 != sizeof(struct tcphdr)) { unsigned char opt[4 * 15 - sizeof(struct tcphdr)]; unsigned int i, optsize; optsize = tcph.doff * 4 - sizeof(struct tcphdr); if (skb_copy_bits(skb, iphoff+iph.ihl*4 + sizeof(tcph), opt, optsize) < 0) { printk("TRUNCATED"); return; } /* Max length: 127 "OPT (" 15*4*2chars ") " */ printk("OPT ("); for (i = 0; i < optsize; i++) printk("%02X", opt[i]); printk(") "); } break; } case IPPROTO_UDP: { struct udphdr udph; /* Max length: 10 "PROTO=UDP " */ printk("PROTO=UDP "); if (ntohs(iph.frag_off) & IP_OFFSET) break; /* Max length: 25 "INCOMPLETE [65535 bytes] " */ if (skb_copy_bits(skb, iphoff+iph.ihl*4, &udph, sizeof(udph)) < 0) { printk("INCOMPLETE [%u bytes] ", skb->len - iphoff - iph.ihl*4); break; } /* Max length: 20 "SPT=65535 DPT=65535 " */ printk("SPT=%u DPT=%u LEN=%u ", ntohs(udph.source), ntohs(udph.dest), ntohs(udph.len)); break; } case IPPROTO_ICMP: { struct icmphdr icmph; static size_t required_len[NR_ICMP_TYPES+1] = { [ICMP_ECHOREPLY] = 4, [ICMP_DEST_UNREACH] = 8 + sizeof(struct iphdr) + 8, [ICMP_SOURCE_QUENCH] = 8 + sizeof(struct iphdr) + 8, [ICMP_REDIRECT] = 8 + sizeof(struct iphdr) + 8, [ICMP_ECHO] = 4, [ICMP_TIME_EXCEEDED] = 8 + sizeof(struct iphdr) + 8, [ICMP_PARAMETERPROB] = 8 + sizeof(struct iphdr) + 8, [ICMP_TIMESTAMP] = 20, [ICMP_TIMESTAMPREPLY] = 20, [ICMP_ADDRESS] = 12, [ICMP_ADDRESSREPLY] = 12 }; /* Max length: 11 "PROTO=ICMP " */ printk("PROTO=ICMP "); if (ntohs(iph.frag_off) & IP_OFFSET) break; /* Max length: 25 "INCOMPLETE [65535 bytes] " */ if (skb_copy_bits(skb, iphoff+iph.ihl*4, &icmph, sizeof(icmph)) < 0) { printk("INCOMPLETE [%u bytes] ", skb->len - iphoff - iph.ihl*4); break; } /* Max length: 18 "TYPE=255 CODE=255 " */ printk("TYPE=%u CODE=%u ", icmph.type, icmph.code); /* Max length: 25 "INCOMPLETE [65535 bytes] " */ if (icmph.type <= NR_ICMP_TYPES && required_len[icmph.type] && skb->len-iphoff-iph.ihl*4 < required_len[icmph.type]) { printk("INCOMPLETE [%u bytes] ", skb->len - iphoff - iph.ihl*4); break; } switch (icmph.type) { case ICMP_ECHOREPLY: case ICMP_ECHO: /* Max length: 19 "ID=65535 SEQ=65535 " */ printk("ID=%u SEQ=%u ", ntohs(icmph.un.echo.id), ntohs(icmph.un.echo.sequence)); break; case ICMP_PARAMETERPROB: /* Max length: 14 "PARAMETER=255 " */ printk("PARAMETER=%u ", ntohl(icmph.un.gateway) >> 24); break; case ICMP_REDIRECT: /* Max length: 24 "GATEWAY=255.255.255.255 " */ printk("GATEWAY=%u.%u.%u.%u ", NIPQUAD(icmph.un.gateway)); /* Fall through */ case ICMP_DEST_UNREACH: case ICMP_SOURCE_QUENCH: case ICMP_TIME_EXCEEDED: /* Max length: 3+maxlen */ if (!iphoff) { /* Only recurse once. */ printk("["); dump_packet(info, skb, iphoff + iph.ihl*4+sizeof(icmph)); printk("] "); } /* Max length: 10 "MTU=65535 " */ if (icmph.type == ICMP_DEST_UNREACH && icmph.code == ICMP_FRAG_NEEDED) printk("MTU=%u ", ntohs(icmph.un.frag.mtu)); } break; } /* Max Length */ case IPPROTO_AH: { struct ip_auth_hdr ah; if (ntohs(iph.frag_off) & IP_OFFSET) break; /* Max length: 9 "PROTO=AH " */ printk("PROTO=AH "); /* Max length: 25 "INCOMPLETE [65535 bytes] " */ if (skb_copy_bits(skb, iphoff+iph.ihl*4, &ah, sizeof(ah)) < 0) { printk("INCOMPLETE [%u bytes] ", skb->len - iphoff - iph.ihl*4); break; } /* Length: 15 "SPI=0xF1234567 " */ printk("SPI=0x%x ", ntohl(ah.spi)); break; } case IPPROTO_ESP: { struct ip_esp_hdr esph; /* Max length: 10 "PROTO=ESP " */ printk("PROTO=ESP "); if (ntohs(iph.frag_off) & IP_OFFSET) break; /* Max length: 25 "INCOMPLETE [65535 bytes] " */ if (skb_copy_bits(skb, iphoff+iph.ihl*4, &esph, sizeof(esph)) < 0) { printk("INCOMPLETE [%u bytes] ", skb->len - iphoff - iph.ihl*4); break; } /* Length: 15 "SPI=0xF1234567 " */ printk("SPI=0x%x ", ntohl(esph.spi)); break; } /* Max length: 10 "PROTO 255 " */ default: printk("PROTO=%u ", iph.protocol); } /* Proto Max log string length */ /* IP: 40+46+6+11+127 = 230 */ /* TCP: 10+max(25,20+30+13+9+32+11+127) = 252 */ /* UDP: 10+max(25,20) = 35 */ /* ICMP: 11+max(25, 18+25+max(19,14,24+3+n+10,3+n+10)) = 91+n */ /* ESP: 10+max(25)+15 = 50 */ /* AH: 9+max(25)+15 = 49 */ /* unknown: 10 */ /* (ICMP allows recursion one level deep) */ /* maxlen = IP + ICMP + IP + max(TCP,UDP,ICMP,unknown) */ /* maxlen = 230+ 91 + 230 + 252 = 803 */ }
static bool tcp_in_window(const struct nf_conn *ct, struct ip_ct_tcp *state, enum ip_conntrack_dir dir, unsigned int index, const struct sk_buff *skb, unsigned int dataoff, const struct tcphdr *tcph, u_int8_t pf) { struct net *net = nf_ct_net(ct); struct ip_ct_tcp_state *sender = &state->seen[dir]; struct ip_ct_tcp_state *receiver = &state->seen[!dir]; const struct nf_conntrack_tuple *tuple = &ct->tuplehash[dir].tuple; __u32 seq, ack, sack, end, win, swin; s16 receiver_offset; bool res; /* * Get the required data from the packet. */ seq = ntohl(tcph->seq); ack = sack = ntohl(tcph->ack_seq); win = ntohs(tcph->window); end = segment_seq_plus_len(seq, skb->len, dataoff, tcph); if (receiver->flags & IP_CT_TCP_FLAG_SACK_PERM) tcp_sack(skb, dataoff, tcph, &sack); /* Take into account NAT sequence number mangling */ receiver_offset = NAT_OFFSET(pf, ct, !dir, ack - 1); ack -= receiver_offset; sack -= receiver_offset; pr_debug("tcp_in_window: START\n"); pr_debug("tcp_in_window: "); nf_ct_dump_tuple(tuple); pr_debug("seq=%u ack=%u+(%d) sack=%u+(%d) win=%u end=%u\n", seq, ack, receiver_offset, sack, receiver_offset, win, end); pr_debug("tcp_in_window: sender end=%u maxend=%u maxwin=%u scale=%i " "receiver end=%u maxend=%u maxwin=%u scale=%i\n", sender->td_end, sender->td_maxend, sender->td_maxwin, sender->td_scale, receiver->td_end, receiver->td_maxend, receiver->td_maxwin, receiver->td_scale); if (sender->td_maxwin == 0) { /* * Initialize sender data. */ if (tcph->syn) { /* * SYN-ACK in reply to a SYN * or SYN from reply direction in simultaneous open. */ sender->td_end = sender->td_maxend = end; sender->td_maxwin = (win == 0 ? 1 : win); tcp_options(skb, dataoff, tcph, sender); /* * RFC 1323: * Both sides must send the Window Scale option * to enable window scaling in either direction. */ if (!(sender->flags & IP_CT_TCP_FLAG_WINDOW_SCALE && receiver->flags & IP_CT_TCP_FLAG_WINDOW_SCALE)) sender->td_scale = receiver->td_scale = 0; if (!tcph->ack) /* Simultaneous open */ return true; } else { /* * We are in the middle of a connection, * its history is lost for us. * Let's try to use the data from the packet. */ sender->td_end = end; sender->td_maxwin = (win == 0 ? 1 : win); sender->td_maxend = end + sender->td_maxwin; } } else if (((state->state == TCP_CONNTRACK_SYN_SENT && dir == IP_CT_DIR_ORIGINAL) || (state->state == TCP_CONNTRACK_SYN_RECV && dir == IP_CT_DIR_REPLY)) && after(end, sender->td_end)) { /* * RFC 793: "if a TCP is reinitialized ... then it need * not wait at all; it must only be sure to use sequence * numbers larger than those recently used." */ sender->td_end = sender->td_maxend = end; sender->td_maxwin = (win == 0 ? 1 : win); tcp_options(skb, dataoff, tcph, sender); } if (!(tcph->ack)) { /* * If there is no ACK, just pretend it was set and OK. */ ack = sack = receiver->td_end; } else if (((tcp_flag_word(tcph) & (TCP_FLAG_ACK|TCP_FLAG_RST)) == (TCP_FLAG_ACK|TCP_FLAG_RST)) && (ack == 0)) { /* * Broken TCP stacks, that set ACK in RST packets as well * with zero ack value. */ ack = sack = receiver->td_end; } if (seq == end && (!tcph->rst || (seq == 0 && state->state == TCP_CONNTRACK_SYN_SENT))) /* * Packets contains no data: we assume it is valid * and check the ack value only. * However RST segments are always validated by their * SEQ number, except when seq == 0 (reset sent answering * SYN. */ seq = end = sender->td_end; pr_debug("tcp_in_window: "); nf_ct_dump_tuple(tuple); pr_debug("seq=%u ack=%u+(%d) sack=%u+(%d) win=%u end=%u\n", seq, ack, receiver_offset, sack, receiver_offset, win, end); pr_debug("tcp_in_window: sender end=%u maxend=%u maxwin=%u scale=%i " "receiver end=%u maxend=%u maxwin=%u scale=%i\n", sender->td_end, sender->td_maxend, sender->td_maxwin, sender->td_scale, receiver->td_end, receiver->td_maxend, receiver->td_maxwin, receiver->td_scale); pr_debug("tcp_in_window: I=%i II=%i III=%i IV=%i\n", before(seq, sender->td_maxend + 1), after(end, sender->td_end - receiver->td_maxwin - 1), before(sack, receiver->td_end + 1), after(sack, receiver->td_end - MAXACKWINDOW(sender) - 1)); if (before(seq, sender->td_maxend + 1) && after(end, sender->td_end - receiver->td_maxwin - 1) && before(sack, receiver->td_end + 1) && after(sack, receiver->td_end - MAXACKWINDOW(sender) - 1)) { /* * Take into account window scaling (RFC 1323). */ if (!tcph->syn) win <<= sender->td_scale; /* * Update sender data. */ swin = win + (sack - ack); if (sender->td_maxwin < swin) sender->td_maxwin = swin; if (after(end, sender->td_end)) { sender->td_end = end; sender->flags |= IP_CT_TCP_FLAG_DATA_UNACKNOWLEDGED; } if (tcph->ack) { if (!(sender->flags & IP_CT_TCP_FLAG_MAXACK_SET)) { sender->td_maxack = ack; sender->flags |= IP_CT_TCP_FLAG_MAXACK_SET; } else if (after(ack, sender->td_maxack)) sender->td_maxack = ack; } /* * Update receiver data. */ if (after(end, sender->td_maxend)) receiver->td_maxwin += end - sender->td_maxend; if (after(sack + win, receiver->td_maxend - 1)) { receiver->td_maxend = sack + win; if (win == 0) receiver->td_maxend++; } if (ack == receiver->td_end) receiver->flags &= ~IP_CT_TCP_FLAG_DATA_UNACKNOWLEDGED; /* * Check retransmissions. */ if (index == TCP_ACK_SET) { if (state->last_dir == dir && state->last_seq == seq && state->last_ack == ack && state->last_end == end && state->last_win == win) state->retrans++; else { state->last_dir = dir; state->last_seq = seq; state->last_ack = ack; state->last_end = end; state->last_win = win; state->retrans = 0; } } res = true; } else { res = false; if (sender->flags & IP_CT_TCP_FLAG_BE_LIBERAL || nf_ct_tcp_be_liberal) res = true; if (!res && LOG_INVALID(net, IPPROTO_TCP)) nf_log_packet(pf, 0, skb, NULL, NULL, NULL, "nf_ct_tcp: %s ", before(seq, sender->td_maxend + 1) ? after(end, sender->td_end - receiver->td_maxwin - 1) ? before(sack, receiver->td_end + 1) ? after(sack, receiver->td_end - MAXACKWINDOW(sender) - 1) ? "BUG" : "ACK is under the lower bound (possible overly delayed ACK)" : "ACK is over the upper bound (ACKed data not seen yet)" : "SEQ is under the lower bound (already ACKed data retransmitted)" : "SEQ is over the upper bound (over the window of the receiver)"); } pr_debug("tcp_in_window: res=%u sender end=%u maxend=%u maxwin=%u " "receiver end=%u maxend=%u maxwin=%u\n", res, sender->td_end, sender->td_maxend, sender->td_maxwin, receiver->td_end, receiver->td_maxend, receiver->td_maxwin); return res; }
/* One level of recursion won't kill us */ static void dump_packet(const struct nf_loginfo *info, const struct sk_buff *skb, unsigned int iphoff) { struct iphdr _iph; const struct iphdr *ih; unsigned int logflags; #if defined(AEI_LOG_FIREWALL_DROP) unsigned char _tmpstr[128]={0}; #endif if (info->type == NF_LOG_TYPE_LOG) logflags = info->u.log.logflags; else logflags = NF_LOG_MASK; ih = skb_header_pointer(skb, iphoff, sizeof(_iph), &_iph); if (ih == NULL) { #if defined(AEI_LOG_FIREWALL_DROP) strcat(_logstr,"TRUNCATED"); #else printk("TRUNCATED"); #endif return; } /* Important fields: * TOS, len, DF/MF, fragment offset, TTL, src, dst, options. */ /* Max length: 40 "SRC=255.255.255.255 DST=255.255.255.255 " */ #if defined(AEI_LOG_FIREWALL_DROP) snprintf(_tmpstr, sizeof(_tmpstr), "SRC=%pI4 DST=%pI4 ", &ih->saddr, &ih->daddr); strcat(_logstr, _tmpstr); #else printk("SRC=%pI4 DST=%pI4 ", &ih->saddr, &ih->daddr); #endif /* Max length: 46 "LEN=65535 TOS=0xFF PREC=0xFF TTL=255 ID=65535 " */ #if defined(AEI_LOG_FIREWALL_DROP) snprintf(_tmpstr, sizeof(_tmpstr), "LEN=%u TOS=0x%02X PREC=0x%02X TTL=%u ID=%u ", ntohs(ih->tot_len), ih->tos & IPTOS_TOS_MASK, ih->tos & IPTOS_PREC_MASK, ih->ttl, ntohs(ih->id)); strcat(_logstr, _tmpstr); #else printk("LEN=%u TOS=0x%02X PREC=0x%02X TTL=%u ID=%u ", ntohs(ih->tot_len), ih->tos & IPTOS_TOS_MASK, ih->tos & IPTOS_PREC_MASK, ih->ttl, ntohs(ih->id)); #endif /* Max length: 6 "CE DF MF " */ if (ntohs(ih->frag_off) & IP_CE) #if defined(AEI_LOG_FIREWALL_DROP) strcat(_logstr,"CE "); #else printk("CE "); #endif if (ntohs(ih->frag_off) & IP_DF) #if defined(AEI_LOG_FIREWALL_DROP) strcat(_logstr,"DF "); #else printk("DF "); #endif if (ntohs(ih->frag_off) & IP_MF) #if defined(AEI_LOG_FIREWALL_DROP) strcat(_logstr,"MF "); #else printk("MF "); #endif /* Max length: 11 "FRAG:65535 " */ if (ntohs(ih->frag_off) & IP_OFFSET) #if defined(AEI_LOG_FIREWALL_DROP) { snprintf(_tmpstr, sizeof(_tmpstr), "FRAG:%u ", ntohs(ih->frag_off) & IP_OFFSET); strcat(_logstr, _tmpstr); } #else printk("FRAG:%u ", ntohs(ih->frag_off) & IP_OFFSET); #endif if ((logflags & IPT_LOG_IPOPT) && ih->ihl * 4 > sizeof(struct iphdr)) { const unsigned char *op; unsigned char _opt[4 * 15 - sizeof(struct iphdr)]; unsigned int i, optsize; optsize = ih->ihl * 4 - sizeof(struct iphdr); op = skb_header_pointer(skb, iphoff+sizeof(_iph), optsize, _opt); if (op == NULL) { #if defined(AEI_LOG_FIREWALL_DROP) strcat(_logstr,"TRUNCATED"); #else printk("TRUNCATED"); #endif return; } /* Max length: 127 "OPT (" 15*4*2chars ") " */ #if defined(AEI_LOG_FIREWALL_DROP) strcat(_logstr,"OPT ("); #else printk("OPT ("); #endif for (i = 0; i < optsize; i++) #if defined(AEI_LOG_FIREWALL_DROP) { snprintf(_tmpstr, sizeof(_tmpstr), "%02X", op[i]); strcat(_logstr, _tmpstr); } #else printk("%02X", op[i]); #endif #if defined(AEI_LOG_FIREWALL_DROP) strcat(_logstr,") "); #else printk(") "); #endif } switch (ih->protocol) { case IPPROTO_TCP: { struct tcphdr _tcph; const struct tcphdr *th; /* Max length: 10 "PROTO=TCP " */ #if defined(AEI_LOG_FIREWALL_DROP) strcat(_logstr,"PROTO=TCP "); #else printk("PROTO=TCP "); #endif if (ntohs(ih->frag_off) & IP_OFFSET) break; /* Max length: 25 "INCOMPLETE [65535 bytes] " */ th = skb_header_pointer(skb, iphoff + ih->ihl * 4, sizeof(_tcph), &_tcph); if (th == NULL) { #if defined(AEI_LOG_FIREWALL_DROP) snprintf(_tmpstr, sizeof(_tmpstr), "INCOMPLETE [%u bytes] ", skb->len - iphoff - ih->ihl*4); strcat(_logstr, _tmpstr); #else printk("INCOMPLETE [%u bytes] ", skb->len - iphoff - ih->ihl*4); #endif break; } /* Max length: 20 "SPT=65535 DPT=65535 " */ #if defined(AEI_LOG_FIREWALL_DROP) snprintf(_tmpstr, sizeof(_tmpstr), "SPT=%u DPT=%u ", ntohs(th->source), ntohs(th->dest)); strcat(_logstr, _tmpstr); #else printk("SPT=%u DPT=%u ", ntohs(th->source), ntohs(th->dest)); #endif /* Max length: 30 "SEQ=4294967295 ACK=4294967295 " */ if (logflags & IPT_LOG_TCPSEQ) #if defined(AEI_LOG_FIREWALL_DROP) { snprintf(_tmpstr, sizeof(_tmpstr), "SEQ=%u ACK=%u ", ntohl(th->seq), ntohl(th->ack_seq)); strcat(_logstr, _tmpstr); } #else printk("SEQ=%u ACK=%u ", ntohl(th->seq), ntohl(th->ack_seq)); #endif /* Max length: 13 "WINDOW=65535 " */ #if defined(AEI_LOG_FIREWALL_DROP) snprintf(_tmpstr, sizeof(_tmpstr), "WINDOW=%u ", ntohs(th->window)); strcat(_logstr, _tmpstr); #else printk("WINDOW=%u ", ntohs(th->window)); #endif /* Max length: 9 "RES=0x3F " */ #if defined(AEI_LOG_FIREWALL_DROP) snprintf(_tmpstr, sizeof(_tmpstr), "RES=0x%02x ", (u8)(ntohl(tcp_flag_word(th) & TCP_RESERVED_BITS) >> 22)); strcat(_logstr, _tmpstr); #else printk("RES=0x%02x ", (u8)(ntohl(tcp_flag_word(th) & TCP_RESERVED_BITS) >> 22)); #endif /* Max length: 32 "CWR ECE URG ACK PSH RST SYN FIN " */ if (th->cwr) #if defined(AEI_LOG_FIREWALL_DROP) strcat(_logstr,"CWR "); #else printk("CWR "); #endif if (th->ece) #if defined(AEI_LOG_FIREWALL_DROP) strcat(_logstr,"ECE "); #else printk("ECE "); #endif if (th->urg) #if defined(AEI_LOG_FIREWALL_DROP) strcat(_logstr,"URG "); #else printk("URG "); #endif if (th->ack) #if defined(AEI_LOG_FIREWALL_DROP) strcat(_logstr,"ACK "); #else printk("ACK "); #endif if (th->psh) #if defined(AEI_LOG_FIREWALL_DROP) strcat(_logstr,"PSH "); #else printk("PSH "); #endif if (th->rst) #if defined(AEI_LOG_FIREWALL_DROP) strcat(_logstr,"RST "); #else printk("RST "); #endif if (th->syn) #if defined(AEI_LOG_FIREWALL_DROP) strcat(_logstr,"SYN "); #else printk("SYN "); #endif if (th->fin) #if defined(AEI_LOG_FIREWALL_DROP) strcat(_logstr,"FIN "); #else printk("FIN "); #endif /* Max length: 11 "URGP=65535 " */ #if defined(AEI_LOG_FIREWALL_DROP) snprintf(_tmpstr, sizeof(_tmpstr), "URGP=%u ", ntohs(th->urg_ptr)); strcat(_logstr, _tmpstr); #else printk("URGP=%u ", ntohs(th->urg_ptr)); #endif if ((logflags & IPT_LOG_TCPOPT) && th->doff * 4 > sizeof(struct tcphdr)) { unsigned char _opt[4 * 15 - sizeof(struct tcphdr)]; const unsigned char *op; unsigned int i, optsize; optsize = th->doff * 4 - sizeof(struct tcphdr); op = skb_header_pointer(skb, iphoff+ih->ihl*4+sizeof(_tcph), optsize, _opt); if (op == NULL) { #if defined(AEI_LOG_FIREWALL_DROP) strcat(_logstr,"TRUNCATED"); #else printk("TRUNCATED"); #endif return; } /* Max length: 127 "OPT (" 15*4*2chars ") " */ #if defined(AEI_LOG_FIREWALL_DROP) strcat(_logstr,"OPT ("); #else printk("OPT ("); #endif for (i = 0; i < optsize; i++) #if defined(AEI_LOG_FIREWALL_DROP) { snprintf(_tmpstr, sizeof(_tmpstr), "%02X", op[i]); strcat(_logstr, _tmpstr); } #else printk("%02X", op[i]); #endif #if defined(AEI_LOG_FIREWALL_DROP) strcat(_logstr,") "); #else printk(") "); #endif } break; } case IPPROTO_UDP: case IPPROTO_UDPLITE: { struct udphdr _udph; const struct udphdr *uh; if (ih->protocol == IPPROTO_UDP) /* Max length: 10 "PROTO=UDP " */ #if defined(AEI_LOG_FIREWALL_DROP) strcat(_logstr,"PROTO=UDP " ); #else printk("PROTO=UDP " ); #endif else /* Max length: 14 "PROTO=UDPLITE " */ #if defined(AEI_LOG_FIREWALL_DROP) strcat(_logstr,"PROTO=UDPLITE "); #else printk("PROTO=UDPLITE "); #endif if (ntohs(ih->frag_off) & IP_OFFSET) break; /* Max length: 25 "INCOMPLETE [65535 bytes] " */ uh = skb_header_pointer(skb, iphoff+ih->ihl*4, sizeof(_udph), &_udph); if (uh == NULL) { #if defined(AEI_LOG_FIREWALL_DROP) snprintf(_tmpstr, sizeof(_tmpstr), "INCOMPLETE [%u bytes] ", skb->len - iphoff - ih->ihl*4); strcat(_logstr, _tmpstr); #else printk("INCOMPLETE [%u bytes] ", skb->len - iphoff - ih->ihl*4); #endif break; } /* Max length: 20 "SPT=65535 DPT=65535 " */ #if defined(AEI_LOG_FIREWALL_DROP) snprintf(_tmpstr, sizeof(_tmpstr), "SPT=%u DPT=%u LEN=%u ", ntohs(uh->source), ntohs(uh->dest), ntohs(uh->len)); strcat(_logstr, _tmpstr); #else printk("SPT=%u DPT=%u LEN=%u ", ntohs(uh->source), ntohs(uh->dest), ntohs(uh->len)); #endif break; } case IPPROTO_ICMP: { struct icmphdr _icmph; const struct icmphdr *ich; static const size_t required_len[NR_ICMP_TYPES+1] = { [ICMP_ECHOREPLY] = 4, [ICMP_DEST_UNREACH] = 8 + sizeof(struct iphdr), [ICMP_SOURCE_QUENCH] = 8 + sizeof(struct iphdr), [ICMP_REDIRECT] = 8 + sizeof(struct iphdr), [ICMP_ECHO] = 4, [ICMP_TIME_EXCEEDED] = 8 + sizeof(struct iphdr), [ICMP_PARAMETERPROB] = 8 + sizeof(struct iphdr), [ICMP_TIMESTAMP] = 20, [ICMP_TIMESTAMPREPLY] = 20, [ICMP_ADDRESS] = 12, [ICMP_ADDRESSREPLY] = 12 }; /* Max length: 11 "PROTO=ICMP " */ #if defined(AEI_LOG_FIREWALL_DROP) strcat(_logstr,"PROTO=ICMP "); #else printk("PROTO=ICMP "); #endif if (ntohs(ih->frag_off) & IP_OFFSET) break; /* Max length: 25 "INCOMPLETE [65535 bytes] " */ ich = skb_header_pointer(skb, iphoff + ih->ihl * 4, sizeof(_icmph), &_icmph); if (ich == NULL) { #if defined(AEI_LOG_FIREWALL_DROP) snprintf(_tmpstr, sizeof(_tmpstr), "INCOMPLETE [%u bytes] ", skb->len - iphoff - ih->ihl*4); strcat(_logstr, _tmpstr); #else printk("INCOMPLETE [%u bytes] ", skb->len - iphoff - ih->ihl*4); #endif break; } /* Max length: 18 "TYPE=255 CODE=255 " */ #if defined(AEI_LOG_FIREWALL_DROP) snprintf(_tmpstr, sizeof(_tmpstr), "TYPE=%u CODE=%u ", ich->type, ich->code); strcat(_logstr, _tmpstr); #else printk("TYPE=%u CODE=%u ", ich->type, ich->code); #endif /* Max length: 25 "INCOMPLETE [65535 bytes] " */ if (ich->type <= NR_ICMP_TYPES && required_len[ich->type] && skb->len-iphoff-ih->ihl*4 < required_len[ich->type]) { #if defined(AEI_LOG_FIREWALL_DROP) snprintf(_tmpstr, sizeof(_tmpstr), "INCOMPLETE [%u bytes] ", skb->len - iphoff - ih->ihl*4); strcat(_logstr, _tmpstr); #else printk("INCOMPLETE [%u bytes] ", skb->len - iphoff - ih->ihl*4); #endif break; } switch (ich->type) { case ICMP_ECHOREPLY: case ICMP_ECHO: /* Max length: 19 "ID=65535 SEQ=65535 " */ #if defined(AEI_LOG_FIREWALL_DROP) snprintf(_tmpstr, sizeof(_tmpstr), "ID=%u SEQ=%u ", ntohs(ich->un.echo.id), ntohs(ich->un.echo.sequence)); strcat(_logstr, _tmpstr); #else printk("ID=%u SEQ=%u ", ntohs(ich->un.echo.id), ntohs(ich->un.echo.sequence)); #endif break; case ICMP_PARAMETERPROB: /* Max length: 14 "PARAMETER=255 " */ #if defined(AEI_LOG_FIREWALL_DROP) snprintf(_tmpstr, sizeof(_tmpstr), "PARAMETER=%u ", ntohl(ich->un.gateway) >> 24); strcat(_logstr, _tmpstr); #else printk("PARAMETER=%u ", ntohl(ich->un.gateway) >> 24); #endif break; case ICMP_REDIRECT: /* Max length: 24 "GATEWAY=255.255.255.255 " */ #if defined(AEI_LOG_FIREWALL_DROP) snprintf(_tmpstr, sizeof(_tmpstr), "GATEWAY=%pI4 ", &ich->un.gateway); strcat(_logstr, _tmpstr); #else printk("GATEWAY=%pI4 ", &ich->un.gateway); #endif /* Fall through */ case ICMP_DEST_UNREACH: case ICMP_SOURCE_QUENCH: case ICMP_TIME_EXCEEDED: /* Max length: 3+maxlen */ if (!iphoff) { /* Only recurse once. */ #if defined(AEI_LOG_FIREWALL_DROP) strcat(_logstr,"["); #else printk("["); #endif dump_packet(info, skb, iphoff + ih->ihl*4+sizeof(_icmph)); #if defined(AEI_LOG_FIREWALL_DROP) strcat(_logstr,"] "); #else printk("] "); #endif } /* Max length: 10 "MTU=65535 " */ if (ich->type == ICMP_DEST_UNREACH && ich->code == ICMP_FRAG_NEEDED) #if defined(AEI_LOG_FIREWALL_DROP) { snprintf(_tmpstr, sizeof(_tmpstr), "MTU=%u ", ntohs(ich->un.frag.mtu)); strcat(_logstr, _tmpstr); } #else printk("MTU=%u ", ntohs(ich->un.frag.mtu)); #endif } break; } /* Max Length */ case IPPROTO_AH: { struct ip_auth_hdr _ahdr; const struct ip_auth_hdr *ah; if (ntohs(ih->frag_off) & IP_OFFSET) break; /* Max length: 9 "PROTO=AH " */ #if defined(AEI_LOG_FIREWALL_DROP) strcat(_logstr,"PROTO=AH "); #else printk("PROTO=AH "); #endif /* Max length: 25 "INCOMPLETE [65535 bytes] " */ ah = skb_header_pointer(skb, iphoff+ih->ihl*4, sizeof(_ahdr), &_ahdr); if (ah == NULL) { #if defined(AEI_LOG_FIREWALL_DROP) snprintf(_tmpstr, sizeof(_tmpstr), "INCOMPLETE [%u bytes] ", skb->len - iphoff - ih->ihl*4); strcat(_logstr, _tmpstr); #else printk("INCOMPLETE [%u bytes] ", skb->len - iphoff - ih->ihl*4); #endif break; } /* Length: 15 "SPI=0xF1234567 " */ #if defined(AEI_LOG_FIREWALL_DROP) snprintf(_tmpstr, sizeof(_tmpstr), "SPI=0x%x ", ntohl(ah->spi)); strcat(_logstr, _tmpstr); #else printk("SPI=0x%x ", ntohl(ah->spi)); #endif break; } case IPPROTO_ESP: { struct ip_esp_hdr _esph; const struct ip_esp_hdr *eh; /* Max length: 10 "PROTO=ESP " */ #if defined(AEI_LOG_FIREWALL_DROP) strcat(_logstr,"PROTO=ESP "); #else printk("PROTO=ESP "); #endif if (ntohs(ih->frag_off) & IP_OFFSET) break; /* Max length: 25 "INCOMPLETE [65535 bytes] " */ eh = skb_header_pointer(skb, iphoff+ih->ihl*4, sizeof(_esph), &_esph); if (eh == NULL) { #if defined(AEI_LOG_FIREWALL_DROP) snprintf(_tmpstr, sizeof(_tmpstr), "INCOMPLETE [%u bytes] ", skb->len - iphoff - ih->ihl*4); strcat(_logstr, _tmpstr); #else printk("INCOMPLETE [%u bytes] ", skb->len - iphoff - ih->ihl*4); #endif break; } /* Length: 15 "SPI=0xF1234567 " */ #if defined(AEI_LOG_FIREWALL_DROP) snprintf(_tmpstr, sizeof(_tmpstr), "SPI=0x%x ", ntohl(eh->spi)); strcat(_logstr, _tmpstr); #else printk("SPI=0x%x ", ntohl(eh->spi)); #endif break; } /* Max length: 10 "PROTO 255 " */ default: #if defined(AEI_LOG_FIREWALL_DROP) snprintf(_tmpstr, sizeof(_tmpstr), "PROTO=%u ", ih->protocol); strcat(_logstr, _tmpstr); #else printk("PROTO=%u ", ih->protocol); #endif }