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 
51 EXPORT_SYMBOL
52 struct 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 
104 EXPORT_SYMBOL
105 uint8_t *pktb_data(struct pkt_buff *pktb)
106 {
107  return pktb->data;
108 }
109 
118 EXPORT_SYMBOL
119 uint32_t pktb_len(struct pkt_buff *pktb)
120 {
121  return pktb->len;
122 }
123 
128 EXPORT_SYMBOL
129 void pktb_free(struct pkt_buff *pktb)
130 {
131  free(pktb);
132 }
133 
165 EXPORT_SYMBOL
166 void pktb_push(struct pkt_buff *pktb, unsigned int len)
167 {
168  pktb->data -= len;
169  pktb->len += len;
170 }
171 
177 EXPORT_SYMBOL
178 void pktb_pull(struct pkt_buff *pktb, unsigned int len)
179 {
180  pktb->data += len;
181  pktb->len -= len;
182 }
183 
189 EXPORT_SYMBOL
190 void pktb_put(struct pkt_buff *pktb, unsigned int len)
191 {
192  pktb->len += len;
193 }
194 
200 EXPORT_SYMBOL
201 void pktb_trim(struct pkt_buff *pktb, unsigned int len)
202 {
203  pktb->len = len;
204 }
205 
219 EXPORT_SYMBOL
220 unsigned int pktb_tailroom(struct pkt_buff *pktb)
221 {
222  return pktb->data_len - pktb->len;
223 }
224 
232 EXPORT_SYMBOL
233 uint8_t *pktb_mac_header(struct pkt_buff *pktb)
234 {
235  return pktb->mac_header;
236 }
237 
244 EXPORT_SYMBOL
245 uint8_t *pktb_network_header(struct pkt_buff *pktb)
246 {
247  return pktb->network_header;
248 }
249 
259 EXPORT_SYMBOL
260 uint8_t *pktb_transport_header(struct pkt_buff *pktb)
261 {
262  return pktb->transport_header;
263 }
264 
269 static 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 
282 static 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 
313 EXPORT_SYMBOL
314 int 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 
358 EXPORT_SYMBOL
359 bool pktb_mangled(const struct pkt_buff *pktb)
360 {
361  return pktb->mangled;
362 }
363 
bool pktb_mangled(const struct pkt_buff *pktb)
Definition: pktbuff.c:359
uint8_t * pktb_transport_header(struct pkt_buff *pktb)
Definition: pktbuff.c:260
uint8_t * pktb_data(struct pkt_buff *pktb)
Definition: pktbuff.c:105
struct pkt_buff * pktb_alloc(int family, void *data, size_t len, size_t extra)
Definition: pktbuff.c:52
void pktb_trim(struct pkt_buff *pktb, unsigned int len)
Definition: pktbuff.c:201
uint8_t * pktb_mac_header(struct pkt_buff *pktb)
Definition: pktbuff.c:233
void pktb_put(struct pkt_buff *pktb, unsigned int len)
Definition: pktbuff.c:190
void pktb_push(struct pkt_buff *pktb, unsigned int len)
Definition: pktbuff.c:166
void pktb_free(struct pkt_buff *pktb)
Definition: pktbuff.c:129
void pktb_pull(struct pkt_buff *pktb, unsigned int len)
Definition: pktbuff.c:178
uint8_t * pktb_network_header(struct pkt_buff *pktb)
Definition: pktbuff.c:245
uint32_t pktb_len(struct pkt_buff *pktb)
Definition: pktbuff.c:119
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
unsigned int pktb_tailroom(struct pkt_buff *pktb)
Definition: pktbuff.c:220