libnetfilter_queue  1.0.3
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 <stdlib.h>
13 #include <string.h> /* for memcpy */
14 #include <stdbool.h>
15 
16 #include <netinet/if_ether.h>
17 #include <netinet/ip.h>
18 #include <netinet/tcp.h>
19 
20 #include "internal.h"
21 
43 struct pkt_buff *
44 pktb_alloc(int family, void *data, size_t len, size_t extra)
45 {
46  struct pkt_buff *pktb;
47  void *pkt_data;
48 
49  pktb = calloc(1, sizeof(struct pkt_buff) + len + extra);
50  if (pktb == NULL)
51  return NULL;
52 
53  /* Better make sure alignment is correct. */
54  pkt_data = (uint8_t *)pktb + sizeof(struct pkt_buff);
55  memcpy(pkt_data, data, len);
56 
57  pktb->len = len;
58  pktb->data_len = len + extra;
59 
60  pktb->head = pkt_data;
61  pktb->data = pkt_data;
62  pktb->tail = pktb->head + len;
63 
64  switch(family) {
65  case AF_INET:
66  pktb->network_header = pktb->data;
67  break;
68  case AF_BRIDGE: {
69  struct ethhdr *ethhdr = (struct ethhdr *)pktb->data;
70 
71  pktb->mac_header = pktb->data;
72 
73  switch(ethhdr->h_proto) {
74  case ETH_P_IP:
75  pktb->network_header = pktb->data + ETH_HLEN;
76  break;
77  default:
78  /* This protocol is unsupported. */
79  free(pktb);
80  return NULL;
81  }
82  break;
83  }
84  }
85  return pktb;
86 }
87 EXPORT_SYMBOL(pktb_alloc);
88 
93 uint8_t *pktb_data(struct pkt_buff *pktb)
94 {
95  return pktb->data;
96 }
97 EXPORT_SYMBOL(pktb_data);
98 
103 uint32_t pktb_len(struct pkt_buff *pktb)
104 {
105  return pktb->len;
106 }
107 EXPORT_SYMBOL(pktb_len);
108 
113 void pktb_free(struct pkt_buff *pktb)
114 {
115  free(pktb);
116 }
117 EXPORT_SYMBOL(pktb_free);
118 
123 void pktb_push(struct pkt_buff *pktb, unsigned int len)
124 {
125  pktb->data -= len;
126  pktb->len += len;
127 }
128 EXPORT_SYMBOL(pktb_push);
129 
134 void pktb_pull(struct pkt_buff *pktb, unsigned int len)
135 {
136  pktb->data += len;
137  pktb->len -= len;
138 }
139 EXPORT_SYMBOL(pktb_pull);
140 
145 void pktb_put(struct pkt_buff *pktb, unsigned int len)
146 {
147  pktb->tail += len;
148  pktb->len += len;
149 }
150 EXPORT_SYMBOL(pktb_put);
151 
156 void pktb_trim(struct pkt_buff *pktb, unsigned int len)
157 {
158  pktb->len = len;
159 }
160 EXPORT_SYMBOL(pktb_trim);
161 
166 unsigned int pktb_tailroom(struct pkt_buff *pktb)
167 {
168  return pktb->data_len - pktb->len;
169 }
170 EXPORT_SYMBOL(pktb_tailroom);
171 
176 uint8_t *pktb_mac_header(struct pkt_buff *pktb)
177 {
178  return pktb->mac_header;
179 }
180 EXPORT_SYMBOL(pktb_mac_header);
181 
186 uint8_t *pktb_network_header(struct pkt_buff *pktb)
187 {
188  return pktb->network_header;
189 }
190 EXPORT_SYMBOL(pktb_network_header);
191 
196 uint8_t *pktb_transport_header(struct pkt_buff *pktb)
197 {
198  return pktb->transport_header;
199 }
200 EXPORT_SYMBOL(pktb_transport_header);
201 
202 static int pktb_expand_tail(struct pkt_buff *pkt, int extra)
203 {
204  /* No room in packet, cannot mangle it. We don't support dynamic
205  * reallocation. Instead, increase the size of the extra room in
206  * the tail in pktb_alloc.
207  */
208  if (pkt->len + extra > pkt->data_len)
209  return 0;
210 
211  pkt->len += extra;
212  pkt->tail = pkt->tail + extra;
213  return 1;
214 }
215 
216 static int enlarge_pkt(struct pkt_buff *pkt, unsigned int extra)
217 {
218  if (pkt->len + extra > 65535)
219  return 0;
220 
221  if (!pktb_expand_tail(pkt, extra - pktb_tailroom(pkt)))
222  return 0;
223 
224  return 1;
225 }
226 
227 int pktb_mangle(struct pkt_buff *pkt,
228  unsigned int dataoff,
229  unsigned int match_offset,
230  unsigned int match_len,
231  const char *rep_buffer,
232  unsigned int rep_len)
233 {
234  unsigned char *data;
235 
236  if (rep_len > match_len &&
237  rep_len - match_len > pktb_tailroom(pkt) &&
238  !enlarge_pkt(pkt, rep_len - match_len))
239  return 0;
240 
241  data = pkt->network_header + dataoff;
242 
243  /* move post-replacement */
244  memmove(data + match_offset + rep_len,
245  data + match_offset + match_len,
246  pkt->tail - (pkt->network_header + dataoff +
247  match_offset + match_len));
248 
249  /* insert data from buffer */
250  memcpy(data + match_offset, rep_buffer, rep_len);
251 
252  /* update pkt info */
253  if (rep_len > match_len)
254  pktb_put(pkt, rep_len - match_len);
255  else
256  pktb_trim(pkt, pkt->len + rep_len - match_len);
257 
258  pkt->mangled = true;
259  return 1;
260 }
261 EXPORT_SYMBOL(pktb_mangle);
262 
267 bool pktb_mangled(const struct pkt_buff *pkt)
268 {
269  return pkt->mangled;
270 }
271 EXPORT_SYMBOL(pktb_mangled);
272 
void pktb_pull(struct pkt_buff *pktb, unsigned int len)
Definition: pktbuff.c:134
uint8_t * pktb_network_header(struct pkt_buff *pktb)
Definition: pktbuff.c:186
uint8_t * pktb_data(struct pkt_buff *pktb)
Definition: pktbuff.c:93
bool pktb_mangled(const struct pkt_buff *pkt)
Definition: pktbuff.c:267
unsigned int pktb_tailroom(struct pkt_buff *pktb)
Definition: pktbuff.c:166
struct pkt_buff * pktb_alloc(int family, void *data, size_t len, size_t extra)
Definition: pktbuff.c:44
void pktb_put(struct pkt_buff *pktb, unsigned int len)
Definition: pktbuff.c:145
uint8_t * pktb_mac_header(struct pkt_buff *pktb)
Definition: pktbuff.c:176
void pktb_trim(struct pkt_buff *pktb, unsigned int len)
Definition: pktbuff.c:156
void pktb_push(struct pkt_buff *pktb, unsigned int len)
Definition: pktbuff.c:123
void pktb_free(struct pkt_buff *pktb)
Definition: pktbuff.c:113
uint32_t pktb_len(struct pkt_buff *pktb)
Definition: pktbuff.c:103
uint8_t * pktb_transport_header(struct pkt_buff *pktb)
Definition: pktbuff.c:196