libnetfilter_queue 1.0.5
pktbuff.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 <errno.h>
13#include <stdlib.h>
14#include <string.h> /* for memcpy */
15#include <stdbool.h>
16
17#include <netinet/if_ether.h>
18#include <netinet/ip.h>
19#include <netinet/tcp.h>
20
21#include "internal.h"
22
51EXPORT_SYMBOL
52struct pkt_buff *pktb_alloc(int family, void *data, size_t len, size_t extra)
53{
54 struct pkt_buff *pktb;
55 struct ethhdr *ethhdr;
56 void *pkt_data;
57
58 pktb = calloc(1, sizeof(struct pkt_buff) + len + extra);
59 if (pktb == NULL)
60 return NULL;
61
62 /* Better make sure alignment is correct. */
63 pkt_data = (uint8_t *)pktb + sizeof(struct pkt_buff);
64 memcpy(pkt_data, data, len);
65
66 pktb->len = len;
67 pktb->data_len = len + extra;
68
69 pktb->data = pkt_data;
70
71 switch(family) {
72 case AF_INET:
73 case AF_INET6:
74 pktb->network_header = pktb->data;
75 break;
76 case AF_BRIDGE:
77 ethhdr = (struct ethhdr *)pktb->data;
78 pktb->mac_header = pktb->data;
79
80 switch(ethhdr->h_proto) {
81 case ETH_P_IP:
82 case ETH_P_IPV6:
83 pktb->network_header = pktb->data + ETH_HLEN;
84 break;
85 default:
86 /* This protocol is unsupported. */
87 errno = EPROTONOSUPPORT;
88 free(pktb);
89 return NULL;
90 }
91 break;
92 }
93 return pktb;
94}
95
104EXPORT_SYMBOL
105uint8_t *pktb_data(struct pkt_buff *pktb)
106{
107 return pktb->data;
108}
109
118EXPORT_SYMBOL
119uint32_t pktb_len(struct pkt_buff *pktb)
120{
121 return pktb->len;
122}
123
128EXPORT_SYMBOL
129void pktb_free(struct pkt_buff *pktb)
130{
131 free(pktb);
132}
133
165EXPORT_SYMBOL
166void pktb_push(struct pkt_buff *pktb, unsigned int len)
167{
168 pktb->data -= len;
169 pktb->len += len;
170}
171
177EXPORT_SYMBOL
178void pktb_pull(struct pkt_buff *pktb, unsigned int len)
179{
180 pktb->data += len;
181 pktb->len -= len;
182}
183
189EXPORT_SYMBOL
190void pktb_put(struct pkt_buff *pktb, unsigned int len)
191{
192 pktb->len += len;
193}
194
200EXPORT_SYMBOL
201void pktb_trim(struct pkt_buff *pktb, unsigned int len)
202{
203 pktb->len = len;
204}
205
219EXPORT_SYMBOL
220unsigned int pktb_tailroom(struct pkt_buff *pktb)
221{
222 return pktb->data_len - pktb->len;
223}
224
232EXPORT_SYMBOL
233uint8_t *pktb_mac_header(struct pkt_buff *pktb)
234{
235 return pktb->mac_header;
236}
237
244EXPORT_SYMBOL
245uint8_t *pktb_network_header(struct pkt_buff *pktb)
246{
247 return pktb->network_header;
248}
249
259EXPORT_SYMBOL
260uint8_t *pktb_transport_header(struct pkt_buff *pktb)
261{
262 return pktb->transport_header;
263}
264
269static int pktb_expand_tail(struct pkt_buff *pktb, int extra)
270{
271 /* No room in packet, cannot mangle it. We don't support dynamic
272 * reallocation. Instead, increase the size of the extra room in
273 * the tail in pktb_alloc.
274 */
275 if (pktb->len + extra > pktb->data_len)
276 return 0;
277
278 pktb->len += extra;
279 return 1;
280}
281
282static int enlarge_pkt(struct pkt_buff *pktb, unsigned int extra)
283{
284 if (pktb->len + extra > 65535)
285 return 0;
286
287 if (!pktb_expand_tail(pktb, extra - pktb_tailroom(pktb)))
288 return 0;
289
290 return 1;
291}
292
313EXPORT_SYMBOL
314int pktb_mangle(struct pkt_buff *pktb,
315 int dataoff,
316 unsigned int match_offset,
317 unsigned int match_len,
318 const char *rep_buffer,
319 unsigned int rep_len)
320{
321 unsigned char *data;
322
323 if (rep_len > match_len &&
324 rep_len - match_len > pktb_tailroom(pktb) &&
325 !enlarge_pkt(pktb, rep_len - match_len))
326 return 0;
327
328 data = pktb->network_header + dataoff;
329
330 /* move post-replacement */
331 memmove(data + match_offset + rep_len,
332 data + match_offset + match_len,
333 pktb_tail(pktb) - (pktb->network_header + dataoff +
334 match_offset + match_len));
335
336 /* insert data from buffer */
337 memcpy(data + match_offset, rep_buffer, rep_len);
338
339 /* update packet info */
340 if (rep_len > match_len)
341 pktb_put(pktb, rep_len - match_len);
342 else
343 pktb_trim(pktb, pktb->len + rep_len - match_len);
344
345 pktb->mangled = true;
346 return 1;
347}
348
358EXPORT_SYMBOL
359bool pktb_mangled(const struct pkt_buff *pktb)
360{
361 return pktb->mangled;
362}
363
uint8_t * pktb_mac_header(struct pkt_buff *pktb)
Definition pktbuff.c:233
uint8_t * pktb_transport_header(struct pkt_buff *pktb)
Definition pktbuff.c:260
unsigned int pktb_tailroom(struct pkt_buff *pktb)
Definition pktbuff.c:220
uint8_t * pktb_network_header(struct pkt_buff *pktb)
Definition pktbuff.c:245
int pktb_mangle(struct pkt_buff *pktb, int dataoff, unsigned int match_offset, unsigned int match_len, const char *rep_buffer, unsigned int rep_len)
Definition pktbuff.c:314
void pktb_free(struct pkt_buff *pktb)
Definition pktbuff.c:129
struct pkt_buff * pktb_alloc(int family, void *data, size_t len, size_t extra)
Definition pktbuff.c:52
uint32_t pktb_len(struct pkt_buff *pktb)
Definition pktbuff.c:119
uint8_t * pktb_data(struct pkt_buff *pktb)
Definition pktbuff.c:105
bool pktb_mangled(const struct pkt_buff *pktb)
Definition pktbuff.c:359
void pktb_trim(struct pkt_buff *pktb, unsigned int len)
Definition pktbuff.c:201
void pktb_pull(struct pkt_buff *pktb, unsigned int len)
Definition pktbuff.c:178
void pktb_push(struct pkt_buff *pktb, unsigned int len)
Definition pktbuff.c:166
void pktb_put(struct pkt_buff *pktb, unsigned int len)
Definition pktbuff.c:190