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
42EXPORT_SYMBOL
43struct 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
61EXPORT_SYMBOL
62void *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
83EXPORT_SYMBOL
84unsigned 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
107EXPORT_SYMBOL
108void 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
125EXPORT_SYMBOL
126void 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 */
142union 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
159EXPORT_SYMBOL
160int 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
218EXPORT_SYMBOL
219int 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
253EXPORT_SYMBOL
254int 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
273
274 return 1;
275}
276
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
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
void nfq_tcp_compute_checksum_ipv6(struct tcphdr *tcph, struct ip6_hdr *ip6h)
Definition: tcp.c:126
void nfq_tcp_compute_checksum_ipv4(struct tcphdr *tcph, struct iphdr *iph)
Definition: tcp.c:108
void * nfq_tcp_get_payload(struct tcphdr *tcph, struct pkt_buff *pktb)
Definition: tcp.c:62
int nfq_tcp_snprintf(char *buf, size_t size, const struct tcphdr *tcph)
Definition: tcp.c:160
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
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
unsigned int nfq_tcp_get_payload_len(struct tcphdr *tcph, struct pkt_buff *pktb)
Definition: tcp.c:84
struct tcphdr * nfq_tcp_get_hdr(struct pkt_buff *pktb)
Definition: tcp.c:43