Deleted Added
full compact
ip_divert.c (200580) ip_divert.c (201527)
1/*-
2 * Copyright (c) 1982, 1986, 1988, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 14 unchanged lines hidden (view full) ---

23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include <sys/cdefs.h>
1/*-
2 * Copyright (c) 1982, 1986, 1988, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 14 unchanged lines hidden (view full) ---

23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include <sys/cdefs.h>
31__FBSDID("$FreeBSD: head/sys/netinet/ip_divert.c 200580 2009-12-15 16:15:14Z luigi $");
31__FBSDID("$FreeBSD: head/sys/netinet/ip_divert.c 201527 2010-01-04 19:01:22Z luigi $");
32
33#if !defined(KLD_MODULE)
34#include "opt_inet.h"
35#include "opt_ipfw.h"
36#include "opt_sctp.h"
37#ifndef INET
38#error "IPDIVERT requires INET."
39#endif

--- 7 unchanged lines hidden (view full) ---

47#include <sys/lock.h>
48#include <sys/malloc.h>
49#include <sys/mbuf.h>
50#include <sys/module.h>
51#include <sys/kernel.h>
52#include <sys/priv.h>
53#include <sys/proc.h>
54#include <sys/protosw.h>
32
33#if !defined(KLD_MODULE)
34#include "opt_inet.h"
35#include "opt_ipfw.h"
36#include "opt_sctp.h"
37#ifndef INET
38#error "IPDIVERT requires INET."
39#endif

--- 7 unchanged lines hidden (view full) ---

47#include <sys/lock.h>
48#include <sys/malloc.h>
49#include <sys/mbuf.h>
50#include <sys/module.h>
51#include <sys/kernel.h>
52#include <sys/priv.h>
53#include <sys/proc.h>
54#include <sys/protosw.h>
55#include <sys/rwlock.h>
56#include <sys/signalvar.h>
57#include <sys/socket.h>
58#include <sys/socketvar.h>
55#include <sys/socket.h>
56#include <sys/socketvar.h>
59#include <sys/sx.h>
60#include <sys/sysctl.h>
57#include <sys/sysctl.h>
61#include <sys/systm.h>
62
58
63#include <vm/uma.h>
64
65#include <net/if.h>
66#include <net/netisr.h>
59#include <net/if.h>
60#include <net/netisr.h>
67#include <net/route.h>
68#include <net/vnet.h>
69
70#include <netinet/in.h>
71#include <netinet/in_pcb.h>
72#include <netinet/in_systm.h>
73#include <netinet/in_var.h>
74#include <netinet/ip.h>
61#include <net/vnet.h>
62
63#include <netinet/in.h>
64#include <netinet/in_pcb.h>
65#include <netinet/in_systm.h>
66#include <netinet/in_var.h>
67#include <netinet/ip.h>
75#include <netinet/ip_divert.h>
76#include <netinet/ip_var.h>
77#include <netinet/ip_fw.h>
78#include <netinet/ipfw/ip_fw_private.h>
79#ifdef SCTP
80#include <netinet/sctp_crc32.h>
81#endif
82
83#include <security/mac/mac_framework.h>

--- 105 unchanged lines hidden (view full) ---

189 hashdestroy(V_divcbinfo.ipi_porthashbase, M_PCB,
190 V_divcbinfo.ipi_porthashmask);
191}
192
193/*
194 * IPPROTO_DIVERT is not in the real IP protocol number space; this
195 * function should never be called. Just in case, drop any packets.
196 */
68#include <netinet/ip_var.h>
69#include <netinet/ip_fw.h>
70#include <netinet/ipfw/ip_fw_private.h>
71#ifdef SCTP
72#include <netinet/sctp_crc32.h>
73#endif
74
75#include <security/mac/mac_framework.h>

--- 105 unchanged lines hidden (view full) ---

181 hashdestroy(V_divcbinfo.ipi_porthashbase, M_PCB,
182 V_divcbinfo.ipi_porthashmask);
183}
184
185/*
186 * IPPROTO_DIVERT is not in the real IP protocol number space; this
187 * function should never be called. Just in case, drop any packets.
188 */
197void
189static void
198div_input(struct mbuf *m, int off)
199{
200
201 KMOD_IPSTAT_INC(ips_noproto);
202 m_freem(m);
203}
204
205/*

--- 7 unchanged lines hidden (view full) ---

213{
214 struct ip *ip;
215 struct inpcb *inp;
216 struct socket *sa;
217 u_int16_t nport;
218 struct sockaddr_in divsrc;
219 struct m_tag *mtag;
220
190div_input(struct mbuf *m, int off)
191{
192
193 KMOD_IPSTAT_INC(ips_noproto);
194 m_freem(m);
195}
196
197/*

--- 7 unchanged lines hidden (view full) ---

205{
206 struct ip *ip;
207 struct inpcb *inp;
208 struct socket *sa;
209 u_int16_t nport;
210 struct sockaddr_in divsrc;
211 struct m_tag *mtag;
212
221 mtag = m_tag_find(m, PACKET_TAG_DIVERT, NULL);
213 mtag = m_tag_locate(m, MTAG_IPFW_RULE, 0, NULL);
222 if (mtag == NULL) {
214 if (mtag == NULL) {
223 printf("%s: no divert tag\n", __func__);
224 m_freem(m);
225 return;
226 }
227 /* Assure header */
228 if (m->m_len < sizeof(struct ip) &&
229 (m = m_pullup(m, sizeof(struct ip))) == 0)
230 return;
231 ip = mtod(m, struct ip *);

--- 8 unchanged lines hidden (view full) ---

240#ifdef SCTP
241 if (m->m_pkthdr.csum_flags & CSUM_SCTP) {
242 ip->ip_len = ntohs(ip->ip_len);
243 sctp_delayed_cksum(m);
244 m->m_pkthdr.csum_flags &= ~CSUM_SCTP;
245 ip->ip_len = htons(ip->ip_len);
246 }
247#endif
215 m_freem(m);
216 return;
217 }
218 /* Assure header */
219 if (m->m_len < sizeof(struct ip) &&
220 (m = m_pullup(m, sizeof(struct ip))) == 0)
221 return;
222 ip = mtod(m, struct ip *);

--- 8 unchanged lines hidden (view full) ---

231#ifdef SCTP
232 if (m->m_pkthdr.csum_flags & CSUM_SCTP) {
233 ip->ip_len = ntohs(ip->ip_len);
234 sctp_delayed_cksum(m);
235 m->m_pkthdr.csum_flags &= ~CSUM_SCTP;
236 ip->ip_len = htons(ip->ip_len);
237 }
238#endif
239 bzero(&divsrc, sizeof(divsrc));
240 divsrc.sin_len = sizeof(divsrc);
241 divsrc.sin_family = AF_INET;
242 /* record matching rule, in host format */
243 divsrc.sin_port = ((struct ipfw_rule_ref *)(mtag+1))->rulenum;
248 /*
249 * Record receive interface address, if any.
250 * But only for incoming packets.
251 */
244 /*
245 * Record receive interface address, if any.
246 * But only for incoming packets.
247 */
252 bzero(&divsrc, sizeof(divsrc));
253 divsrc.sin_len = sizeof(divsrc);
254 divsrc.sin_family = AF_INET;
255 divsrc.sin_port = divert_cookie(mtag); /* record matching rule */
256 if (incoming) {
257 struct ifaddr *ifa;
258 struct ifnet *ifp;
259
260 /* Sanity check */
261 M_ASSERTPKTHDR(m);
262
263 /* Find IP address for receive interface */

--- 31 unchanged lines hidden (view full) ---

295 * (see div_output for the other half of this.)
296 */
297 strlcpy(divsrc.sin_zero, m->m_pkthdr.rcvif->if_xname,
298 sizeof(divsrc.sin_zero));
299 }
300
301 /* Put packet on socket queue, if any */
302 sa = NULL;
248 if (incoming) {
249 struct ifaddr *ifa;
250 struct ifnet *ifp;
251
252 /* Sanity check */
253 M_ASSERTPKTHDR(m);
254
255 /* Find IP address for receive interface */

--- 31 unchanged lines hidden (view full) ---

287 * (see div_output for the other half of this.)
288 */
289 strlcpy(divsrc.sin_zero, m->m_pkthdr.rcvif->if_xname,
290 sizeof(divsrc.sin_zero));
291 }
292
293 /* Put packet on socket queue, if any */
294 sa = NULL;
303 nport = htons((u_int16_t)divert_info(mtag));
295 nport = htons((u_int16_t)(((struct ipfw_rule_ref *)(mtag+1))->info));
304 INP_INFO_RLOCK(&V_divcbinfo);
305 LIST_FOREACH(inp, &V_divcb, inp_list) {
306 /* XXX why does only one socket match? */
307 if (inp->inp_lport == nport) {
308 INP_RLOCK(inp);
309 sa = inp->inp_socket;
310 SOCKBUF_LOCK(&sa->so_rcv);
311 if (sbappendaddr_locked(&sa->so_rcv,

--- 22 unchanged lines hidden (view full) ---

334 * otherwise, send to ip_input() and mark as having been received on
335 * the interface with that address.
336 */
337static int
338div_output(struct socket *so, struct mbuf *m, struct sockaddr_in *sin,
339 struct mbuf *control)
340{
341 struct m_tag *mtag;
296 INP_INFO_RLOCK(&V_divcbinfo);
297 LIST_FOREACH(inp, &V_divcb, inp_list) {
298 /* XXX why does only one socket match? */
299 if (inp->inp_lport == nport) {
300 INP_RLOCK(inp);
301 sa = inp->inp_socket;
302 SOCKBUF_LOCK(&sa->so_rcv);
303 if (sbappendaddr_locked(&sa->so_rcv,

--- 22 unchanged lines hidden (view full) ---

326 * otherwise, send to ip_input() and mark as having been received on
327 * the interface with that address.
328 */
329static int
330div_output(struct socket *so, struct mbuf *m, struct sockaddr_in *sin,
331 struct mbuf *control)
332{
333 struct m_tag *mtag;
342 struct divert_tag *dt;
334 struct ipfw_rule_ref *dt;
343 int error = 0;
344 struct mbuf *options;
345
346 /*
347 * An mbuf may hasn't come from userland, but we pretend
348 * that it has.
349 */
350 m->m_pkthdr.rcvif = NULL;
351 m->m_nextpkt = NULL;
352 M_SETFIB(m, so->so_fibnum);
353
354 if (control)
355 m_freem(control); /* XXX */
356
335 int error = 0;
336 struct mbuf *options;
337
338 /*
339 * An mbuf may hasn't come from userland, but we pretend
340 * that it has.
341 */
342 m->m_pkthdr.rcvif = NULL;
343 m->m_nextpkt = NULL;
344 M_SETFIB(m, so->so_fibnum);
345
346 if (control)
347 m_freem(control); /* XXX */
348
357 if ((mtag = m_tag_find(m, PACKET_TAG_DIVERT, NULL)) == NULL) {
358 mtag = m_tag_get(PACKET_TAG_DIVERT, sizeof(struct divert_tag),
359 M_NOWAIT | M_ZERO);
349 mtag = m_tag_locate(m, MTAG_IPFW_RULE, 0, NULL);
350 if (mtag == NULL) {
351 /* this should be normal */
352 mtag = m_tag_alloc(MTAG_IPFW_RULE, 0,
353 sizeof(struct ipfw_rule_ref), M_NOWAIT | M_ZERO);
360 if (mtag == NULL) {
361 error = ENOBUFS;
362 goto cantsend;
363 }
354 if (mtag == NULL) {
355 error = ENOBUFS;
356 goto cantsend;
357 }
364 dt = (struct divert_tag *)(mtag+1);
365 m_tag_prepend(m, mtag);
358 m_tag_prepend(m, mtag);
366 } else
367 dt = (struct divert_tag *)(mtag+1);
359 }
360 dt = (struct ipfw_rule_ref *)(mtag+1);
368
369 /* Loopback avoidance and state recovery */
370 if (sin) {
371 int i;
372
361
362 /* Loopback avoidance and state recovery */
363 if (sin) {
364 int i;
365
373 dt->cookie = sin->sin_port;
366 /* set the starting point. We provide a non-zero slot,
367 * but a non_matching chain_id to skip that info and use
368 * the rulenum/rule_id.
369 */
370 dt->slot = 1; /* dummy, chain_id is invalid */
371 dt->chain_id = 0;
372 dt->rulenum = sin->sin_port+1; /* host format ? */
373 dt->rule_id = 0;
374 /*
375 * Find receive interface with the given name, stuffed
376 * (if it exists) in the sin_zero[] field.
377 * The name is user supplied data so don't trust its size
378 * or that it is zero terminated.
379 */
380 for (i = 0; i < sizeof(sin->sin_zero) && sin->sin_zero[i]; i++)
381 ;
382 if ( i > 0 && i < sizeof(sin->sin_zero))
383 m->m_pkthdr.rcvif = ifunit(sin->sin_zero);
384 }
385
386 /* Reinject packet into the system as incoming or outgoing */
387 if (!sin || sin->sin_addr.s_addr == 0) {
388 struct ip *const ip = mtod(m, struct ip *);
389 struct inpcb *inp;
390
374 /*
375 * Find receive interface with the given name, stuffed
376 * (if it exists) in the sin_zero[] field.
377 * The name is user supplied data so don't trust its size
378 * or that it is zero terminated.
379 */
380 for (i = 0; i < sizeof(sin->sin_zero) && sin->sin_zero[i]; i++)
381 ;
382 if ( i > 0 && i < sizeof(sin->sin_zero))
383 m->m_pkthdr.rcvif = ifunit(sin->sin_zero);
384 }
385
386 /* Reinject packet into the system as incoming or outgoing */
387 if (!sin || sin->sin_addr.s_addr == 0) {
388 struct ip *const ip = mtod(m, struct ip *);
389 struct inpcb *inp;
390
391 dt->info |= IP_FW_DIVERT_OUTPUT_FLAG;
391 dt->info |= IPFW_IS_DIVERT | IPFW_INFO_OUT;
392 INP_INFO_WLOCK(&V_divcbinfo);
393 inp = sotoinpcb(so);
394 INP_RLOCK(inp);
395 /*
396 * Don't allow both user specified and setsockopt options,
397 * and don't allow packet length sizes that will crash
398 */
399 if (((ip->ip_hl != (sizeof (*ip) >> 2)) && inp->inp_options) ||

--- 49 unchanged lines hidden (view full) ---

449 error = ip_output(m, options, NULL,
450 ((so->so_options & SO_DONTROUTE) ?
451 IP_ROUTETOIF : 0) | IP_ALLOWBROADCAST |
452 IP_RAWOUTPUT, NULL, NULL);
453 if (options != NULL)
454 m_freem(options);
455 }
456 } else {
392 INP_INFO_WLOCK(&V_divcbinfo);
393 inp = sotoinpcb(so);
394 INP_RLOCK(inp);
395 /*
396 * Don't allow both user specified and setsockopt options,
397 * and don't allow packet length sizes that will crash
398 */
399 if (((ip->ip_hl != (sizeof (*ip) >> 2)) && inp->inp_options) ||

--- 49 unchanged lines hidden (view full) ---

449 error = ip_output(m, options, NULL,
450 ((so->so_options & SO_DONTROUTE) ?
451 IP_ROUTETOIF : 0) | IP_ALLOWBROADCAST |
452 IP_RAWOUTPUT, NULL, NULL);
453 if (options != NULL)
454 m_freem(options);
455 }
456 } else {
457 dt->info |= IP_FW_DIVERT_LOOPBACK_FLAG;
457 dt->info |= IPFW_IS_DIVERT | IPFW_INFO_IN;
458 if (m->m_pkthdr.rcvif == NULL) {
459 /*
460 * No luck with the name, check by IP address.
461 * Clear the port and the ifname to make sure
462 * there are no distractions for ifa_ifwithaddr.
463 */
464 struct ifaddr *ifa;
465

--- 117 unchanged lines hidden (view full) ---

583 m_freem(m);
584 return EINVAL;
585 }
586
587 /* Send packet */
588 return div_output(so, m, (struct sockaddr_in *)nam, control);
589}
590
458 if (m->m_pkthdr.rcvif == NULL) {
459 /*
460 * No luck with the name, check by IP address.
461 * Clear the port and the ifname to make sure
462 * there are no distractions for ifa_ifwithaddr.
463 */
464 struct ifaddr *ifa;
465

--- 117 unchanged lines hidden (view full) ---

583 m_freem(m);
584 return EINVAL;
585 }
586
587 /* Send packet */
588 return div_output(so, m, (struct sockaddr_in *)nam, control);
589}
590
591void
591static void
592div_ctlinput(int cmd, struct sockaddr *sa, void *vip)
593{
594 struct in_addr faddr;
595
596 faddr = ((struct sockaddr_in *)sa)->sin_addr;
597 if (sa->sa_family != AF_INET || faddr.s_addr == INADDR_ANY)
598 return;
599 if (PRC_IS_REDIRECT(cmd))

--- 196 unchanged lines hidden (view full) ---

796
797static moduledata_t ipdivertmod = {
798 "ipdivert",
799 div_modevent,
800 0
801};
802
803DECLARE_MODULE(ipdivert, ipdivertmod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY);
592div_ctlinput(int cmd, struct sockaddr *sa, void *vip)
593{
594 struct in_addr faddr;
595
596 faddr = ((struct sockaddr_in *)sa)->sin_addr;
597 if (sa->sa_family != AF_INET || faddr.s_addr == INADDR_ANY)
598 return;
599 if (PRC_IS_REDIRECT(cmd))

--- 196 unchanged lines hidden (view full) ---

796
797static moduledata_t ipdivertmod = {
798 "ipdivert",
799 div_modevent,
800 0
801};
802
803DECLARE_MODULE(ipdivert, ipdivertmod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY);
804MODULE_DEPEND(dummynet, ipfw, 2, 2, 2);
804MODULE_DEPEND(ipdivert, ipfw, 2, 2, 2);
805MODULE_VERSION(ipdivert, 1);
805MODULE_VERSION(ipdivert, 1);