Index: contrib/pf/pfctl/parse.y =================================================================== --- contrib/pf/pfctl/parse.y (wersja 193371) +++ contrib/pf/pfctl/parse.y (kopia robocza) @@ -207,6 +207,10 @@ char *match_tag; u_int8_t match_tag_not; int rtableid; + struct { + struct node_host *addr; + u_int16_t port; + } divert; } filter_opts; struct antispoof_opts { @@ -403,6 +407,10 @@ int lineno; } YYSTYPE; +#define PPORT_RANGE 1 +#define PPORT_STAR 2 +int parseport(char *, struct range *r, int); + #define DYNIF_MULTIADDR(addr) ((addr).type == PF_ADDR_DYNIFTL && \ (!((addr).iflags & PFI_AFLAG_NOALIAS) || \ !isdigit((addr).v.ifname[strlen((addr).v.ifname)-1]))) @@ -425,7 +433,9 @@ %token STICKYADDRESS MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE %token MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH %token TAGGED TAG IFBOUND FLOATING STATEPOLICY ROUTE +%token DIVERTTO DIVERTREPLY %token STRING +%token NUMBER %token PORTBINARY %type interface if_list if_item_not if_item %type number icmptype icmp6type uid gid @@ -434,7 +444,7 @@ %type sourcetrack flush unaryop statelock %type action nataction natpass scrubaction %type flags flag blockspec -%type port rport +%type portplain portstar portrange %type hashkey %type proto proto_list proto_item %type icmpspec @@ -451,7 +461,8 @@ %type gids gid_list gid_item %type route %type redirection redirpool -%type label string tag anchorname +%type label stringall tag anchorname +%type string varstring numberstring %type keep %type state_opt_spec state_opt_list state_opt_item %type logquick quick log logopts logopt @@ -631,7 +642,15 @@ } ; -string : string STRING { +stringall : STRING { $$ = $1; } + | ALL { + if (($$ = strdup("all")) == NULL) { + err(1, "stringall: strdup"); + } + } + ; + +string : STRING string { if (asprintf(&$$, "%s %s", $1, $2) == -1) err(1, "string: asprintf"); free($1); @@ -640,7 +659,27 @@ | STRING ; -varset : STRING '=' string { +varstring : numberstring varstring { + if (asprintf(&$$, "%s %s", $1, $2) == -1) + err(1, "string: asprintf"); + free($1); + free($2); + } + | numberstring + ; + +numberstring : NUMBER { + char *s; + if (asprintf(&s, "%lld", (long long)$1) == -1) { + yyerror("string: asprintf"); + YYERROR; + } + $$ = s; + } + | STRING + ; + +varset : STRING '=' varstring { if (pf->opts & PF_OPT_VERBOSE) printf("%s = \"%s\"\n", $1, $3); if (symset($1, $3, 0) == -1) @@ -2028,6 +2067,31 @@ free($9.queues.pqname); } + if ((r.divert.port = $9.divert.port)) { + if (r.direction == PF_OUT) { + if ($9.divert.addr) { + yyerror("address specified " + "for outgoing divert"); + YYERROR; + } + bzero(&r.divert.addr, + sizeof(r.divert.addr)); + } else { + if (!$9.divert.addr) { + yyerror("no address specified " + "for incoming divert"); + YYERROR; + } + if ($9.divert.addr->af != r.af) { + yyerror("address family " + "mismatch for divert"); + YYERROR; + } + r.divert.addr = + $9.divert.addr->addr.v.a.addr; + } + } + expand_rule(&r, $4, $5.host, $7, $8.src_os, $8.src.host, $8.src.port, $8.dst.host, $8.dst.port, $9.uid, $9.gid, $9.icmpspec, ""); @@ -2155,6 +2219,23 @@ #endif filter_opts.rtableid = $2; } + | DIVERTTO STRING PORT portplain { + if ((filter_opts.divert.addr = host($2)) == NULL) { + yyerror("could not parse divert address: %s", + $2); + free($2); + YYERROR; + } + free($2); + filter_opts.divert.port = $4.a; + if (!filter_opts.divert.port) { + yyerror("invalid divert port: %u", ntohs($4.a)); + YYERROR; + } + } + | DIVERTREPLY { + filter_opts.divert.port = 1; /* some random value */ + } ; action : PASS { $$.b1 = PF_PASS; $$.b2 = $$.w = 0; } @@ -2649,7 +2730,7 @@ } ; -port_item : port { +port_item : portrange { $$ = calloc(1, sizeof(struct node_port)); if ($$ == NULL) err(1, "port_item: calloc"); @@ -2662,7 +2743,7 @@ $$->next = NULL; $$->tail = $$; } - | unaryop port { + | unaryop portrange { if ($2.t) { yyerror("':' cannot be used with an other " "port operator"); @@ -2677,7 +2758,7 @@ $$->next = NULL; $$->tail = $$; } - | port PORTBINARY port { + | portrange PORTBINARY portrange { if ($1.t || $3.t) { yyerror("':' cannot be used with an other " "port operator"); @@ -2694,31 +2775,23 @@ } ; -port : STRING { - char *p = strchr($1, ':'); +portplain : numberstring { + if (parseport($1, &$$, 0) == -1) { + free($1); + YYERROR; + } + free($1); + } + ; - if (p == NULL) { - if (($$.a = getservice($1)) == -1) { - free($1); - YYERROR; - } - $$.b = $$.t = 0; - } else { - int port[2]; - - *p++ = 0; - if ((port[0] = getservice($1)) == -1 || - (port[1] = getservice(p)) == -1) { - free($1); - YYERROR; - } - $$.a = port[0]; - $$.b = port[1]; - $$.t = PF_OP_RRG; - } +portrange : numberstring { + if (parseport($1, &$$, PPORT_RANGE) == -1) { + free($1); + YYERROR; + } free($1); - } - ; + } + ; uids : uid_item { $$ = $1; } | '{' uid_list '}' { $$ = $2; } @@ -3265,38 +3338,15 @@ | NO { $$ = 1; } ; -rport : STRING { - char *p = strchr($1, ':'); +portstar : numberstring { + if (parseport($1, &$$, PPORT_RANGE|PPORT_STAR) == -1) { + free($1); + YYERROR; + } + free($1); + } + ; - if (p == NULL) { - if (($$.a = getservice($1)) == -1) { - free($1); - YYERROR; - } - $$.b = $$.t = 0; - } else if (!strcmp(p+1, "*")) { - *p = 0; - if (($$.a = getservice($1)) == -1) { - free($1); - YYERROR; - } - $$.b = 0; - $$.t = 1; - } else { - *p++ = 0; - if (($$.a = getservice($1)) == -1 || - ($$.b = getservice(p)) == -1) { - free($1); - YYERROR; - } - if ($$.a == $$.b) - $$.b = 0; - $$.t = 0; - } - free($1); - } - ; - redirspec : host { $$ = $1; } | '{' redir_host_list '}' { $$ = $2; } ; @@ -3317,7 +3367,7 @@ $$->host = $2; $$->rport.a = $$->rport.b = $$->rport.t = 0; } - | ARROW redirspec PORT rport { + | ARROW redirspec PORT portstar { $$ = calloc(1, sizeof(struct redirection)); if ($$ == NULL) err(1, "redirection: calloc"); @@ -3443,7 +3493,7 @@ $$->host = $2; $$->rport.a = $$->rport.b = $$->rport.t = 0; } - | ARROW host PORT rport { + | ARROW host PORT portstar { $$ = calloc(1, sizeof(struct redirection)); if ($$ == NULL) err(1, "redirection: calloc"); @@ -4891,6 +4941,8 @@ { "code", CODE}, { "crop", FRAGCROP}, { "debug", DEBUG}, + { "divert-reply", DIVERTREPLY}, + { "divert-to", DIVERTTO}, { "drop", DROP}, { "drop-ovl", FRAGDROP}, { "dup-to", DUPTO}, @@ -5495,6 +5547,41 @@ } int +parseport(char *port, struct range *r, int extensions) +{ + char *p = strchr(port, ':'); + + if (p == NULL) { + if ((r->a = getservice(port)) == -1) + return (-1); + r->b = 0; + r->t = PF_OP_NONE; + return (0); + } + if ((extensions & PPORT_STAR) && !strcmp(p+1, "*")) { + *p = 0; + if ((r->a = getservice(port)) == -1) + return (-1); + r->b = 0; + r->t = PF_OP_IRG; + return (0); + } + if ((extensions & PPORT_RANGE)) { + *p++ = 0; + if ((r->a = getservice(port)) == -1 || + (r->b = getservice(p)) == -1) + return (-1); + if (r->a == r->b) { + r->b = 0; + r->t = PF_OP_NONE; + } else + r->t = PF_OP_RRG; + return (0); + } + return (-1); +} + +int pfctl_load_anchors(int dev, struct pfctl *pf, struct pfr_buffer *trans) { struct loadanchors *la; Index: contrib/pf/pfctl/pfctl_parser.c =================================================================== --- contrib/pf/pfctl/pfctl_parser.c (wersja 193371) +++ contrib/pf/pfctl/pfctl_parser.c (kopia robocza) @@ -994,6 +994,22 @@ } if (r->rtableid != -1) printf(" rtable %u", r->rtableid); + if (r->divert.port) { + if (PF_AZERO(&r->divert.addr, r->af)) { + printf(" divert-reply"); + } else { + /* XXX cut&paste from print_addr */ + char buf[48]; + + printf(" divert-to "); + if (inet_ntop(r->af, &r->divert.addr, buf, + sizeof(buf)) == NULL) + printf("?"); + else + printf("%s", buf); + printf(" %u", ntohs(r->divert.port)); + } + } if (!anchor_call[0] && (r->action == PF_NAT || r->action == PF_BINAT || r->action == PF_RDR)) { printf(" -> "); Index: sys/conf/options =================================================================== --- sys/conf/options (wersja 193546) +++ sys/conf/options (kopia robocza) @@ -379,6 +379,7 @@ DEV_PF opt_pf.h DEV_PFLOG opt_pf.h DEV_PFSYNC opt_pf.h +PF_DIVERT opt_pf.h DEV_VLAN opt_vlan.h DUMMYNET opt_ipdn.h ETHER_8022 opt_ef.h Index: sys/netinet/tcp_input.c =================================================================== --- sys/netinet/tcp_input.c (wersja 193546) +++ sys/netinet/tcp_input.c (kopia robocza) @@ -32,10 +32,11 @@ #include __FBSDID("$FreeBSD$"); -#include "opt_ipfw.h" /* for ipfw_fwd */ +#include "opt_ipfw.h" /* for IPFIREWALL_FORWARD */ #include "opt_inet.h" #include "opt_inet6.h" #include "opt_ipsec.h" +#include "opt_pf.h" /* for PF_DIVERT */ #include "opt_tcpdebug.h" #include @@ -319,7 +320,7 @@ int thflags; int rstreason = 0; /* For badport_bandlim accounting purposes */ uint8_t iptos; -#ifdef IPFIREWALL_FORWARD +#if defined(IPFIREWALL_FORWARD) || defined(PF_DIVERT) struct m_tag *fwd_tag; #endif #ifdef INET6 @@ -515,7 +516,7 @@ panic("%s: findpcb ti_locked %d\n", __func__, ti_locked); #endif -#ifdef IPFIREWALL_FORWARD +#if defined(IPFIREWALL_FORWARD) || defined(PF_DIVERT) /* * Grab info from PACKET_TAG_IPFORWARD tag prepended to the chain. */ @@ -547,7 +548,7 @@ /* Remove the tag from the packet. We don't need it anymore. */ m_tag_delete(m, fwd_tag); } else -#endif /* IPFIREWALL_FORWARD */ +#endif /* IPFIREWALL_FORWARD || PF_DIVERT */ { if (isipv6) { #ifdef INET6 Index: sys/netinet/in.h =================================================================== --- sys/netinet/in.h (wersja 193546) +++ sys/netinet/in.h (kopia robocza) @@ -442,6 +442,7 @@ #define IP_ONESBCAST 23 /* bool: send all-ones broadcast */ #define IP_BINDANY 24 /* bool: allow bind to any address */ +#define IP_RECVDSTPORT 25 /* bool: receive IP dst port w/dgram */ #define IP_FW_TABLE_ADD 40 /* add entry */ #define IP_FW_TABLE_DEL 41 /* delete entry */ Index: sys/netinet/raw_ip.c =================================================================== --- sys/netinet/raw_ip.c (wersja 193546) +++ sys/netinet/raw_ip.c (kopia robocza) @@ -33,8 +33,10 @@ #include __FBSDID("$FreeBSD$"); +#include "opt_ipfw.h" /* for IPFIREWALL_FORWARD */ #include "opt_inet6.h" #include "opt_ipsec.h" +#include "opt_pf.h" /* for PF_DIVERT */ #include "opt_route.h" #include @@ -263,6 +265,9 @@ struct inpcb *inp, *last; struct sockaddr_in ripsrc; int hash; +#if defined(IPFIREWALL_FORWARD) || defined(PF_DIVERT) + struct m_tag *fwd_tag; +#endif bzero(&ripsrc, sizeof(ripsrc)); ripsrc.sin_len = sizeof(ripsrc); @@ -283,6 +288,19 @@ if ((inp->inp_vflag & INP_IPV4) == 0) continue; #endif +#if defined(IPFIREWALL_FORWARD) || defined(PF_DIVERT) + /* + * Grab info from PACKET_TAG_IPFORWARD tag prepended to the chain. + */ + fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL); + if (fwd_tag != NULL) { + struct sockaddr_in *next_hop; + + next_hop = (struct sockaddr_in *)(fwd_tag + 1); + if (inp->inp_laddr.s_addr != next_hop->sin_addr.s_addr) + continue; + } else +#endif /* IPFIREWALL_FORWARD || PF_DIVERT */ if (inp->inp_laddr.s_addr != ip->ip_dst.s_addr) continue; if (inp->inp_faddr.s_addr != ip->ip_src.s_addr) Index: sys/netinet/in_pcb.h =================================================================== --- sys/netinet/in_pcb.h (wersja 193546) +++ sys/netinet/in_pcb.h (kopia robocza) @@ -412,6 +412,7 @@ #define INP_DONTFRAG 0x00000800 /* don't fragment packet */ #define INP_BINDANY 0x00001000 /* allow bind to any address */ #define INP_INHASHLIST 0x00002000 /* in_pcbinshash() has been called */ +#define INP_RECVDSTPORT 0x00004000 /* receive UDP dst port */ #define IN6P_IPV6_V6ONLY 0x00008000 /* restrict AF_INET6 socket for v6 */ #define IN6P_PKTINFO 0x00010000 /* receive IP6 dst and I/F */ #define IN6P_HOPLIMIT 0x00020000 /* receive hoplimit */ @@ -431,7 +432,7 @@ #define IN6P_MTU 0x80000000 /* receive path MTU */ #define INP_CONTROLOPTS (INP_RECVOPTS|INP_RECVRETOPTS|INP_RECVDSTADDR|\ - INP_RECVIF|INP_RECVTTL|\ + INP_RECVIF|INP_RECVTTL|INP_RECVDSTPORT|\ IN6P_PKTINFO|IN6P_HOPLIMIT|IN6P_HOPOPTS|\ IN6P_DSTOPTS|IN6P_RTHDR|IN6P_RTHDRDSTOPTS|\ IN6P_TCLASS|IN6P_AUTOFLOWLABEL|IN6P_RFC2292|\ Index: sys/netinet/ip_output.c =================================================================== --- sys/netinet/ip_output.c (wersja 193550) +++ sys/netinet/ip_output.c (kopia robocza) @@ -937,6 +937,7 @@ case IP_RECVOPTS: case IP_RECVRETOPTS: case IP_RECVDSTADDR: + case IP_RECVDSTPORT: case IP_RECVTTL: case IP_RECVIF: case IP_FAITH: @@ -984,6 +985,10 @@ OPTSET(INP_RECVDSTADDR); break; + case IP_RECVDSTPORT: + OPTSET(INP_RECVDSTPORT); + break; + case IP_RECVTTL: OPTSET(INP_RECVTTL); break; Index: sys/netinet/ip_input.c =================================================================== --- sys/netinet/ip_input.c (wersja 193546) +++ sys/netinet/ip_input.c (kopia robocza) @@ -36,6 +36,7 @@ #include "opt_ipfw.h" #include "opt_ipstealth.h" #include "opt_ipsec.h" +#include "opt_pf.h" #include "opt_route.h" #include "opt_carp.h" @@ -548,6 +549,18 @@ return; } #endif /* IPFIREWALL_FORWARD */ +#ifdef PF_DIVERT + /* + * If the packet is forwarded by if_bridge, it went through + * ether_demux(), which cleared M_FASTFWD_OURS flag, so we have to + * look for tag as well. + */ + if ((m->m_flags & M_FASTFWD_OURS) != 0 || + m_tag_find(m, PACKET_TAG_IPFORWARD, NULL) != NULL) { + m->m_flags &= ~M_FASTFWD_OURS; + goto ours; + } +#endif /* PF_DIVERT */ passin: /* Index: sys/netinet/udp_usrreq.c =================================================================== --- sys/netinet/udp_usrreq.c (wersja 193549) +++ sys/netinet/udp_usrreq.c (kopia robocza) @@ -37,6 +37,7 @@ #include "opt_ipfw.h" #include "opt_inet6.h" #include "opt_ipsec.h" +#include "opt_pf.h" /* for PF_DIVERT */ #include #include @@ -229,8 +230,8 @@ * into the socket code. */ static void -udp_append(struct inpcb *inp, struct ip *ip, struct mbuf *n, int off, - struct sockaddr_in *udp_in) +udp_append(struct inpcb *inp, struct ip *ip, struct udphdr *uh, struct mbuf *n, + int off, struct sockaddr_in *udp_in) { struct sockaddr *append_sa; struct socket *so; @@ -264,6 +265,14 @@ else #endif ip_savecontrol(inp, &opts, ip, n); + if (inp->inp_flags & INP_RECVDSTPORT) { + struct mbuf **mp = &opts; + + while (*mp) + mp = &(*mp)->m_next; + *mp = sbcreatecontrol((caddr_t) &uh->uh_dport, + sizeof(uh->uh_dport), IP_RECVDSTPORT, IPPROTO_IP); + } } #ifdef INET6 if (inp->inp_vflag & INP_IPV6) { @@ -303,7 +312,7 @@ int len; struct ip save_ip; struct sockaddr_in udp_in; -#ifdef IPFIREWALL_FORWARD +#if defined(IPFIREWALL_FORWARD) || defined(PF_DIVERT) struct m_tag *fwd_tag; #endif @@ -487,7 +496,7 @@ if (up->u_tun_func == NULL) { if (n != NULL) udp_append(last, - ip, n, + ip, uh, n, iphlen + sizeof(struct udphdr), &udp_in); @@ -528,8 +537,8 @@ } up = intoudpcb(last); if (up->u_tun_func == NULL) { - udp_append(last, ip, m, iphlen + sizeof(struct udphdr), - &udp_in); + udp_append(last, ip, uh, m, + iphlen + sizeof(struct udphdr), &udp_in); } else { /* * Engage the tunneling protocol. @@ -544,6 +553,26 @@ /* * Locate pcb for datagram. */ +#ifdef PF_DIVERT + /* + * Grab info from PACKET_TAG_IPFORWARD tag prepended to the chain. + */ + fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL); + if (fwd_tag != NULL) { + struct sockaddr_in *next_hop; + + /* + * Do the hack. + */ + next_hop = (struct sockaddr_in *)(fwd_tag + 1); + inp = in_pcblookup_hash(&V_udbinfo, ip->ip_src, uh->uh_sport, + next_hop->sin_addr, ntohs(next_hop->sin_port), 1, ifp); + /* + * Remove the tag from the packet. We don't need it anymore. + */ + m_tag_delete(m, fwd_tag); + } else +#endif inp = in_pcblookup_hash(&V_udbinfo, ip->ip_src, uh->uh_sport, ip->ip_dst, uh->uh_dport, 1, ifp); if (inp == NULL) { @@ -583,7 +612,8 @@ } up = intoudpcb(inp); if (up->u_tun_func == NULL) { - udp_append(inp, ip, m, iphlen + sizeof(struct udphdr), &udp_in); + udp_append(inp, ip, uh, m, iphlen + sizeof(struct udphdr), + &udp_in); } else { /* * Engage the tunneling protocol. @@ -877,6 +907,10 @@ *(struct in_addr *)CMSG_DATA(cm); break; + case IP_RECVDSTPORT: + /* Ignore for convenience. */ + break; + default: error = ENOPROTOOPT; break; Index: sys/net/if_bridge.c =================================================================== --- sys/net/if_bridge.c (wersja 193546) +++ sys/net/if_bridge.c (kopia robocza) @@ -80,6 +80,7 @@ #include "opt_inet.h" #include "opt_inet6.h" #include "opt_carp.h" +#include "opt_pf.h" #include #include @@ -3154,6 +3155,24 @@ else ip->ip_sum = in_cksum(*mp, hlen); +#ifdef PF_DIVERT + if (((*mp)->m_flags & M_FASTFWD_OURS)) { + /* Put the Ethernet header back on. */ + M_PREPEND(*mp, ETHER_HDR_LEN, M_DONTWAIT); + if (*mp == NULL) + return (error); + eh1 = mtod(*mp, struct ether_header *); + bcopy(&eh2, eh1, ETHER_HDR_LEN); + /* Process packet again. */ + ether_demux(bifp, *mp); + /* + * Return an error, because we don't want mbuf to be + * freed twice. + */ + return (-1); + } +#endif + break; #ifdef INET6 case ETHERTYPE_IPV6: Index: sys/contrib/pf/net/pfvar.h =================================================================== --- sys/contrib/pf/net/pfvar.h (wersja 193546) +++ sys/contrib/pf/net/pfvar.h (kopia robocza) @@ -679,6 +679,11 @@ #define PF_FLUSH 0x01 #define PF_FLUSH_GLOBAL 0x02 u_int8_t flush; + + struct { + struct pf_addr addr; + u_int16_t port; + } divert; }; /* rule flags */ @@ -1290,6 +1295,21 @@ int ref; }; +struct pf_divert { +#ifdef __FreeBSD__ + union { + struct sockaddr_in ipv4; + struct sockaddr_in6 ipv6; + } addr; +#else + union { + struct in_addr ipv4; + struct in6_addr ipv6; + } addr; + u_int16_t port; +#endif +}; + #define PFFRAG_FRENT_HIWAT 5000 /* Number of fragment entries */ #define PFFRAG_FRAG_HIWAT 1000 /* Number of fragmented packets */ #define PFFRAG_FRCENT_HIWAT 50000 /* Number of fragment cache entries */ @@ -1617,6 +1637,7 @@ u_int8_t); void pf_rm_rule(struct pf_rulequeue *, struct pf_rule *); +struct pf_divert *pf_find_divert(struct mbuf *); #ifdef INET #ifdef __FreeBSD__ Index: sys/contrib/pf/net/pf.c =================================================================== --- sys/contrib/pf/net/pf.c (wersja 193546) +++ sys/contrib/pf/net/pf.c (kopia robocza) @@ -304,6 +304,7 @@ struct pf_addr *); int pf_check_proto_cksum(struct mbuf *, int, int, u_int8_t, sa_family_t); +struct pf_divert *pf_get_divert(struct mbuf *); int pf_addr_wrap_neq(struct pf_addr_wrap *, struct pf_addr_wrap *); struct pf_state *pf_find_state_recurse(struct pfi_kif *, @@ -6761,6 +6762,34 @@ } #endif /* __FreeBSD__ */ +struct pf_divert * +pf_find_divert(struct mbuf *m) +{ + struct m_tag *mtag; + + if ((mtag = m_tag_find(m, PACKET_TAG_PF_DIVERT, NULL)) == NULL) + return (NULL); + + return ((struct pf_divert *)(mtag + 1)); +} + +struct pf_divert * +pf_get_divert(struct mbuf *m) +{ + struct m_tag *mtag; + + if ((mtag = m_tag_find(m, PACKET_TAG_PF_DIVERT, NULL)) == NULL) { + mtag = m_tag_get(PACKET_TAG_PF_DIVERT, sizeof(struct pf_divert), + M_NOWAIT); + if (mtag == NULL) + return (NULL); + bzero(mtag + 1, sizeof(struct pf_divert)); + m_tag_prepend(m, mtag); + } + + return ((struct pf_divert *)(mtag + 1)); +} + #ifdef INET int #ifdef __FreeBSD__ @@ -7061,6 +7090,25 @@ (ntohl(pd.dst->v4.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) pd.pf_mtag->flags |= PF_TAG_TRANSLATE_LOCALHOST; + if (dir == PF_IN && action == PF_PASS && r->direction == PF_IN && + r->divert.port > 0) { + struct pf_divert *divert; + + if ((divert = pf_get_divert(m))) { +#ifdef __FreeBSD__ + m->m_flags |= M_FASTFWD_OURS; + divert->addr.ipv4.sin_len = sizeof(divert->addr.ipv4); + divert->addr.ipv4.sin_family = AF_INET; + divert->addr.ipv4.sin_port = ntohs(r->divert.port); + divert->addr.ipv4.sin_addr = r->divert.addr.v4; +#else + m->m_pkthdr.pf.flags |= PF_TAG_DIVERTED; + divert->port = r->divert.port; + divert->addr.ipv4 = r->divert.addr.v4; +#endif + } + } + if (log) { struct pf_rule *lr; @@ -7517,6 +7565,25 @@ IN6_IS_ADDR_LOOPBACK(&pd.dst->v6)) pd.pf_mtag->flags |= PF_TAG_TRANSLATE_LOCALHOST; + if (dir == PF_IN && action == PF_PASS && r->direction == PF_IN && + r->divert.port > 0) { + struct pf_divert *divert; + + if ((divert = pf_get_divert(m))) { +#ifdef __FreeBSD__ + m->m_flags |= M_FASTFWD_OURS; + divert->addr.ipv6.sin6_len = sizeof(divert->addr.ipv6); + divert->addr.ipv6.sin6_family = AF_INET6; + divert->addr.ipv6.sin6_port = ntohs(r->divert.port); + divert->addr.ipv6.sin6_addr = r->divert.addr.v6; +#else + m->m_pkthdr.pf.flags |= PF_TAG_DIVERTED; + divert->port = r->divert.port; + divert->addr.ipv6 = r->divert.addr.v6; +#endif + } + } + if (log) { struct pf_rule *lr; Index: sys/sys/mbuf.h =================================================================== --- sys/sys/mbuf.h (wersja 193546) +++ sys/sys/mbuf.h (kopia robocza) @@ -863,6 +863,7 @@ #define PACKET_TAG_DUMMYNET 15 /* dummynet info */ #define PACKET_TAG_DIVERT 17 /* divert info */ #define PACKET_TAG_IPFORWARD 18 /* ipforward info */ +#define PACKET_TAG_PF_DIVERT PACKET_TAG_IPFORWARD #define PACKET_TAG_MACLABEL (19 | MTAG_PERSISTENT) /* MAC label */ #define PACKET_TAG_PF 21 /* PF + ALTQ information */ #define PACKET_TAG_RTSOCKFAM 25 /* rtsock sa family */