libnetfilter_queue  1.0.5
tcp.c
1 /*
2  * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This code has been sponsored by Vyatta Inc. <http://www.vyatta.com>
10  */
11 
12 #include <stdio.h>
13 #include <string.h> /* for memcpy */
14 #include <stdbool.h>
15 #include <arpa/inet.h>
16 #include <netinet/ip.h>
17 #include <netinet/ip6.h>
18 #define _GNU_SOURCE
19 #include <netinet/tcp.h>
20 
21 #include <libnetfilter_queue/libnetfilter_queue.h>
22 #include <libnetfilter_queue/libnetfilter_queue_tcp.h>
23 #include <libnetfilter_queue/libnetfilter_queue_ipv4.h>
24 #include <libnetfilter_queue/libnetfilter_queue_ipv6.h>
25 #include <libnetfilter_queue/pktbuff.h>
26 
27 #include "internal.h"
28 
42 EXPORT_SYMBOL
43 struct tcphdr *nfq_tcp_get_hdr(struct pkt_buff *pktb)
44 {
45  if (pktb->transport_header == NULL)
46  return NULL;
47 
48  /* No room for the TCP header. */
49  if (pktb_tail(pktb) - pktb->transport_header < sizeof(struct tcphdr))
50  return NULL;
51 
52  return (struct tcphdr *)pktb->transport_header;
53 }
54 
61 EXPORT_SYMBOL
62 void *nfq_tcp_get_payload(struct tcphdr *tcph, struct pkt_buff *pktb)
63 {
64  unsigned int len = tcph->doff * 4;
65 
66  /* TCP packet is too short */
67  if (len < sizeof(struct tcphdr))
68  return NULL;
69 
70  /* malformed TCP data offset. */
71  if (pktb->transport_header + len > pktb_tail(pktb))
72  return NULL;
73 
74  return pktb->transport_header + len;
75 }
76 
83 EXPORT_SYMBOL
84 unsigned int nfq_tcp_get_payload_len(struct tcphdr *tcph, struct pkt_buff *pktb)
85 {
86  return pktb_tail(pktb) - pktb->transport_header - (tcph->doff * 4);
87 }
88 
107 EXPORT_SYMBOL
108 void nfq_tcp_compute_checksum_ipv4(struct tcphdr *tcph, struct iphdr *iph)
109 {
110  /* checksum field in header needs to be zero for calculation. */
111  tcph->check = 0;
112  tcph->check = nfq_checksum_tcpudp_ipv4(iph, IPPROTO_TCP);
113 }
114 
125 EXPORT_SYMBOL
126 void nfq_tcp_compute_checksum_ipv6(struct tcphdr *tcph, struct ip6_hdr *ip6h)
127 {
128  /* checksum field in header needs to be zero for calculation. */
129  tcph->check = 0;
130  tcph->check = nfq_checksum_tcpudp_ipv6(ip6h, tcph, IPPROTO_TCP);
131 }
132 
137 /*
138  * The union cast uses a gcc extension to avoid aliasing problems
139  * (union is compatible to any of its members)
140  * This means this part of the code is -fstrict-aliasing safe now.
141  */
142 union tcp_word_hdr {
143  struct tcphdr hdr;
144  uint32_t words[5];
145 };
146 
147 #define tcp_flag_word(tp) ( ((union tcp_word_hdr *)(tp))->words[3])
148 
159 EXPORT_SYMBOL
160 int nfq_tcp_snprintf(char *buf, size_t size, const struct tcphdr *tcph)
161 {
162  int ret, len = 0;
163 
164 #define TCP_RESERVED_BITS htonl(0x0F000000)
165 
166  ret = snprintf(buf, size, "SPT=%u DPT=%u SEQ=%u ACK=%u "
167  "WINDOW=%u RES=0x%02x ",
168  ntohs(tcph->source), ntohs(tcph->dest),
169  ntohl(tcph->seq), ntohl(tcph->ack_seq),
170  ntohs(tcph->window),
171  (uint8_t)
172  (ntohl(tcp_flag_word(tcph) & TCP_RESERVED_BITS) >> 22));
173  len += ret;
174 
175  if (tcph->urg) {
176  ret = snprintf(buf+len, size-len, "URG ");
177  len += ret;
178  }
179  if (tcph->ack) {
180  ret = snprintf(buf+len, size-len, "ACK ");
181  len += ret;
182  }
183  if (tcph->psh) {
184  ret = snprintf(buf+len, size-len, "PSH ");
185  len += ret;
186  }
187  if (tcph->rst) {
188  ret = snprintf(buf+len, size-len, "RST ");
189  len += ret;
190  }
191  if (tcph->syn) {
192  ret = snprintf(buf+len, size-len, "SYN ");
193  len += ret;
194  }
195  if (tcph->fin) {
196  ret = snprintf(buf+len, size-len, "FIN ");
197  len += ret;
198  }
199  /* XXX: Not TCP options implemented yet, sorry. */
200 
201  return ret;
202 }
203 
218 EXPORT_SYMBOL
219 int nfq_tcp_mangle_ipv4(struct pkt_buff *pktb,
220  unsigned int match_offset, unsigned int match_len,
221  const char *rep_buffer, unsigned int rep_len)
222 {
223  struct iphdr *iph;
224  struct tcphdr *tcph;
225 
226  iph = (struct iphdr *)pktb->network_header;
227  tcph = (struct tcphdr *)(pktb->network_header + iph->ihl*4);
228 
229  if (!nfq_ip_mangle(pktb, iph->ihl*4 + tcph->doff*4,
230  match_offset, match_len, rep_buffer, rep_len))
231  return 0;
232 
234 
235  return 1;
236 }
237 
253 EXPORT_SYMBOL
254 int nfq_tcp_mangle_ipv6(struct pkt_buff *pktb,
255  unsigned int match_offset, unsigned int match_len,
256  const char *rep_buffer, unsigned int rep_len)
257 {
258  struct ip6_hdr *ip6h;
259  struct tcphdr *tcph;
260 
261  ip6h = (struct ip6_hdr *)pktb->network_header;
262  tcph = (struct tcphdr *)(pktb->transport_header);
263  if (!tcph)
264  return 0;
265 
266  if (!nfq_ip6_mangle(pktb,
267  pktb->transport_header - pktb->network_header +
268  tcph->doff * 4,
269  match_offset, match_len, rep_buffer, rep_len))
270  return 0;
271 
272  nfq_tcp_compute_checksum_ipv6(tcph, ip6h);
273 
274  return 1;
275 }
276 
int nfq_ip6_mangle(struct pkt_buff *pktb, unsigned int dataoff, unsigned int match_offset, unsigned int match_len, const char *rep_buffer, unsigned int rep_len)
Definition: ipv6.c:131
int nfq_tcp_mangle_ipv6(struct pkt_buff *pktb, unsigned int match_offset, unsigned int match_len, const char *rep_buffer, unsigned int rep_len)
Definition: tcp.c:254
int nfq_tcp_mangle_ipv4(struct pkt_buff *pktb, unsigned int match_offset, unsigned int match_len, const char *rep_buffer, unsigned int rep_len)
Definition: tcp.c:219
void nfq_tcp_compute_checksum_ipv4(struct tcphdr *tcph, struct iphdr *iph)
Definition: tcp.c:108
struct tcphdr * nfq_tcp_get_hdr(struct pkt_buff *pktb)
Definition: tcp.c:43
int nfq_tcp_snprintf(char *buf, size_t size, const struct tcphdr *tcph)
Definition: tcp.c:160
void nfq_tcp_compute_checksum_ipv6(struct tcphdr *tcph, struct ip6_hdr *ip6h)
Definition: tcp.c:126
unsigned int nfq_tcp_get_payload_len(struct tcphdr *tcph, struct pkt_buff *pktb)
Definition: tcp.c:84
void * nfq_tcp_get_payload(struct tcphdr *tcph, struct pkt_buff *pktb)
Definition: tcp.c:62
int nfq_ip_mangle(struct pkt_buff *pktb, unsigned int dataoff, unsigned int match_offset, unsigned int match_len, const char *rep_buffer, unsigned int rep_len)
Definition: ipv4.c:127