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); |