9de374809c8dc63b32a98811ed6d1f917d918314
[platform/upstream/libnetfilter_queue.git] / src / extra / 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 <arpa/inet.h>
15 #include <netinet/ip.h>
16 #include <netinet/ip6.h>
17 #include <netinet/tcp.h>
18
19 #include <libnetfilter_queue/libnetfilter_queue.h>
20 #include <libnetfilter_queue/libnetfilter_queue_tcp.h>
21 #include <libnetfilter_queue/pktbuff.h>
22
23 #include "internal.h"
24
25 /**
26  * \defgroup tcp TCP helper functions
27  * @{
28  */
29
30 /**
31  * nfq_tcp_get - get the TCP header
32  * \param pktb: pointer to user-space network packet buffer
33  *
34  * This function returns NULL if an invalid TCP header is found. On success,
35  * it returns the TCP header.
36  *
37  * \note You have to call nfq_ip_set_transport_header or
38  * nfq_ip6_set_transport_header first to access the TCP header.
39  */
40 struct tcphdr *nfq_tcp_get_hdr(struct pkt_buff *pktb)
41 {
42         if (pktb->transport_header == NULL)
43                 return NULL;
44
45         /* No room for the TCP header. */
46         if (pktb->tail - pktb->transport_header < sizeof(struct tcphdr))
47                 return NULL;
48
49         return (struct tcphdr *)pktb->transport_header;
50 }
51 EXPORT_SYMBOL(nfq_tcp_get_hdr);
52
53 /**
54  * nfq_tcp_get_payload - get the TCP packet payload
55  * \param tcph: pointer to the TCP header
56  * \param pktb: pointer to user-space network packet buffer
57  */
58 void *nfq_tcp_get_payload(struct tcphdr *tcph, struct pkt_buff *pktb)
59 {
60         unsigned int doff = tcph->doff * 4;
61
62         /* malformed TCP data offset. */
63         if (pktb->transport_header + doff >= pktb->tail)
64                 return NULL;
65
66         return pktb->transport_header + doff;
67 }
68 EXPORT_SYMBOL(nfq_tcp_get_payload);
69
70 /**
71  * nfq_tcp_get_payload_len - get the tcp packet payload
72  * \param tcph: pointer to the TCP header
73  * \param pktb: pointer to user-space network packet buffer
74  */
75 unsigned int
76 nfq_tcp_get_payload_len(struct tcphdr *tcph, struct pkt_buff *pktb)
77 {
78         return pktb->tail - pktb->transport_header;
79 }
80 EXPORT_SYMBOL(nfq_tcp_get_payload_len);
81
82 /**
83  * nfq_tcp_set_checksum_ipv4 - computes IPv4/TCP packet checksum
84  * \param tcph: pointer to the TCP header
85  * \param iph: pointer to the IPv4 header
86  */
87 void
88 nfq_tcp_compute_checksum_ipv4(struct tcphdr *tcph, struct iphdr *iph)
89 {
90         /* checksum field in header needs to be zero for calculation. */
91         tcph->check = 0;
92         tcph->check = checksum_tcpudp_ipv4(iph);
93 }
94 EXPORT_SYMBOL(nfq_tcp_compute_checksum_ipv4);
95
96 /**
97  * nfq_tcp_set_checksum_ipv6 - computes IPv6/TCP packet checksum
98  * \param tcph: pointer to the TCP header
99  * \param iph: pointer to the IPv6 header
100  */
101 void
102 nfq_tcp_compute_checksum_ipv6(struct tcphdr *tcph, struct ip6_hdr *ip6h)
103 {
104         /* checksum field in header needs to be zero for calculation. */
105         tcph->check = 0;
106         tcph->check = checksum_tcpudp_ipv6(ip6h, tcph);
107 }
108 EXPORT_SYMBOL(nfq_tcp_compute_checksum_ipv6);
109
110 /*
111  *      The union cast uses a gcc extension to avoid aliasing problems
112  *  (union is compatible to any of its members)
113  *  This means this part of the code is -fstrict-aliasing safe now.
114  */
115 union tcp_word_hdr {
116         struct tcphdr hdr;
117         uint32_t  words[5];
118 };
119
120 #define tcp_flag_word(tp) ( ((union tcp_word_hdr *)(tp))->words[3])
121
122 /**
123  * nfq_pkt_snprintf_tcp_hdr - print tcp header into one buffer in a humnan
124  * readable way
125  * \param buf: pointer to buffer that is used to print the object
126  * \param size: size of the buffer (or remaining room in it).
127  * \param tcp: pointer to a valid tcp header.
128  *
129  */
130 int nfq_tcp_snprintf(char *buf, size_t size, const struct tcphdr *tcph)
131 {
132         int ret, len = 0;
133
134 #define TCP_RESERVED_BITS htonl(0x0F000000)
135
136         ret = snprintf(buf, size, "SPT=%u DPT=%u SEQ=%u ACK=%u "
137                                    "WINDOW=%u RES=%0x%02x ",
138                         ntohs(tcph->source), ntohs(tcph->dest),
139                         ntohl(tcph->seq), ntohl(tcph->ack_seq),
140                         ntohs(tcph->window),
141                         (uint8_t)(ntohl(tcp_flag_word(tcph) &
142                                 TCP_RESERVED_BITS) >> 22));
143         len += ret;
144
145         if (tcph->urg) {
146                 ret = snprintf(buf+len, size-len, "URG ");
147                 len += ret;
148         }
149         if (tcph->ack) {
150                 ret = snprintf(buf+len, size-len, "ACK ");
151                 len += ret;
152         }
153         if (tcph->psh) {
154                 ret = snprintf(buf+len, size-len, "PSH ");
155                 len += ret;
156         }
157         if (tcph->rst) {
158                 ret = snprintf(buf+len, size-len, "RST ");
159                 len += ret;
160         }
161         if (tcph->syn) {
162                 ret = snprintf(buf+len, size-len, "SYN ");
163                 len += ret;
164         }
165         if (tcph->fin) {
166                 ret = snprintf(buf+len, size-len, "FIN ");
167                 len += ret;
168         }
169         /* Not TCP options implemented yet, sorry. */
170 }
171 EXPORT_SYMBOL(nfq_tcp_snprintf);
172
173 /**
174  * @}
175  */