Changeset View
Standalone View
sys/netpfil/ipfw/ip_fw2.c
Show First 20 Lines • Show All 1,074 Lines • ▼ Show 20 Lines | #ifndef __FreeBSD__ | ||||
return cred_check(insn, proto, oif, | return cred_check(insn, proto, oif, | ||||
dst_ip, dst_port, src_ip, src_port, | dst_ip, dst_port, src_ip, src_port, | ||||
(struct bsd_ucred *)uc, ugid_lookupp, ((struct mbuf *)inp)->m_skb); | (struct bsd_ucred *)uc, ugid_lookupp, ((struct mbuf *)inp)->m_skb); | ||||
#else /* FreeBSD */ | #else /* FreeBSD */ | ||||
struct in_addr src_ip, dst_ip; | struct in_addr src_ip, dst_ip; | ||||
struct inpcbinfo *pi; | struct inpcbinfo *pi; | ||||
struct ipfw_flow_id *id; | struct ipfw_flow_id *id; | ||||
struct inpcb *pcb, *inp; | struct inpcb *pcb, *inp; | ||||
struct ifnet *oif; | |||||
int lookupflags; | int lookupflags; | ||||
int match; | int match; | ||||
id = &args->f_id; | id = &args->f_id; | ||||
inp = args->inp; | inp = args->inp; | ||||
oif = args->oif; | |||||
/* | /* | ||||
* Check to see if the UDP or TCP stack supplied us with | * Check to see if the UDP or TCP stack supplied us with | ||||
* the PCB. If so, rather then holding a lock and looking | * the PCB. If so, rather then holding a lock and looking | ||||
* up the PCB, we can use the one that was supplied. | * up the PCB, we can use the one that was supplied. | ||||
*/ | */ | ||||
if (inp && *ugid_lookupp == 0) { | if (inp && *ugid_lookupp == 0) { | ||||
INP_LOCK_ASSERT(inp); | INP_LOCK_ASSERT(inp); | ||||
Show All 21 Lines | if (id->proto == IPPROTO_TCP) { | ||||
pi = &V_ulitecbinfo; | pi = &V_ulitecbinfo; | ||||
} else | } else | ||||
return 0; | return 0; | ||||
lookupflags |= INPLOOKUP_RLOCKPCB; | lookupflags |= INPLOOKUP_RLOCKPCB; | ||||
match = 0; | match = 0; | ||||
if (*ugid_lookupp == 0) { | if (*ugid_lookupp == 0) { | ||||
if (id->addr_type == 6) { | if (id->addr_type == 6) { | ||||
#ifdef INET6 | #ifdef INET6 | ||||
if (oif == NULL) | if (args->flags & IPFW_ARGS_IN) | ||||
pcb = in6_pcblookup_mbuf(pi, | pcb = in6_pcblookup_mbuf(pi, | ||||
&id->src_ip6, htons(id->src_port), | &id->src_ip6, htons(id->src_port), | ||||
&id->dst_ip6, htons(id->dst_port), | &id->dst_ip6, htons(id->dst_port), | ||||
lookupflags, oif, args->m); | lookupflags, NULL, args->m); | ||||
else | else | ||||
pcb = in6_pcblookup_mbuf(pi, | pcb = in6_pcblookup_mbuf(pi, | ||||
&id->dst_ip6, htons(id->dst_port), | &id->dst_ip6, htons(id->dst_port), | ||||
&id->src_ip6, htons(id->src_port), | &id->src_ip6, htons(id->src_port), | ||||
lookupflags, oif, args->m); | lookupflags, args->ifp, args->m); | ||||
#else | #else | ||||
*ugid_lookupp = -1; | *ugid_lookupp = -1; | ||||
return (0); | return (0); | ||||
#endif | #endif | ||||
} else { | } else { | ||||
src_ip.s_addr = htonl(id->src_ip); | src_ip.s_addr = htonl(id->src_ip); | ||||
dst_ip.s_addr = htonl(id->dst_ip); | dst_ip.s_addr = htonl(id->dst_ip); | ||||
if (oif == NULL) | if (args->flags & IPFW_ARGS_IN) | ||||
pcb = in_pcblookup_mbuf(pi, | pcb = in_pcblookup_mbuf(pi, | ||||
src_ip, htons(id->src_port), | src_ip, htons(id->src_port), | ||||
dst_ip, htons(id->dst_port), | dst_ip, htons(id->dst_port), | ||||
lookupflags, oif, args->m); | lookupflags, NULL, args->m); | ||||
else | else | ||||
pcb = in_pcblookup_mbuf(pi, | pcb = in_pcblookup_mbuf(pi, | ||||
dst_ip, htons(id->dst_port), | dst_ip, htons(id->dst_port), | ||||
src_ip, htons(id->src_port), | src_ip, htons(id->src_port), | ||||
lookupflags, oif, args->m); | lookupflags, args->ifp, args->m); | ||||
} | } | ||||
if (pcb != NULL) { | if (pcb != NULL) { | ||||
INP_RLOCK_ASSERT(pcb); | INP_RLOCK_ASSERT(pcb); | ||||
*uc = crhold(pcb->inp_cred); | *uc = crhold(pcb->inp_cred); | ||||
*ugid_lookupp = 1; | *ugid_lookupp = 1; | ||||
INP_RUNLOCK(pcb); | INP_RUNLOCK(pcb); | ||||
} | } | ||||
if (*ugid_lookupp == 0) { | if (*ugid_lookupp == 0) { | ||||
▲ Show 20 Lines • Show All 93 Lines • ▼ Show 20 Lines | |||||
* | * | ||||
* All arguments are in args so we can modify them and return them | * All arguments are in args so we can modify them and return them | ||||
* back to the caller. | * back to the caller. | ||||
* | * | ||||
* Parameters: | * Parameters: | ||||
* | * | ||||
* args->m (in/out) The packet; we set to NULL when/if we nuke it. | * args->m (in/out) The packet; we set to NULL when/if we nuke it. | ||||
* Starts with the IP header. | * Starts with the IP header. | ||||
* args->eh (in) Mac header if present, NULL for layer3 packet. | |||||
* args->L3offset Number of bytes bypassed if we came from L2. | * args->L3offset Number of bytes bypassed if we came from L2. | ||||
* e.g. often sizeof(eh) ** NOTYET ** | * e.g. often sizeof(eh) ** NOTYET ** | ||||
* args->oif Outgoing interface, NULL if packet is incoming. | * args->ifp Incoming or outgoing interface. | ||||
* The incoming interface is in the mbuf. (in) | |||||
* args->divert_rule (in/out) | * args->divert_rule (in/out) | ||||
* Skip up to the first rule past this rule number; | * Skip up to the first rule past this rule number; | ||||
* upon return, non-zero port number for divert or tee. | * upon return, non-zero port number for divert or tee. | ||||
* | * | ||||
* args->rule Pointer to the last matching rule (in/out) | * args->rule Pointer to the last matching rule (in/out) | ||||
* args->next_hop Socket we are forwarding to (out). | * args->next_hop Socket we are forwarding to (out). | ||||
* args->next_hop6 IPv6 next hop we are forwarding to (out). | * args->next_hop6 IPv6 next hop we are forwarding to (out). | ||||
* args->f_id Addresses grabbed from the packet (out) | * args->f_id Addresses grabbed from the packet (out) | ||||
Show All 19 Lines | ipfw_chk(struct ip_fw_args *args) | ||||
* Local variables holding state while processing a packet: | * Local variables holding state while processing a packet: | ||||
* | * | ||||
* IMPORTANT NOTE: to speed up the processing of rules, there | * IMPORTANT NOTE: to speed up the processing of rules, there | ||||
* are some assumption on the values of the variables, which | * are some assumption on the values of the variables, which | ||||
* are documented here. Should you change them, please check | * are documented here. Should you change them, please check | ||||
* the implementation of the various instructions to make sure | * the implementation of the various instructions to make sure | ||||
* that they still work. | * that they still work. | ||||
* | * | ||||
* args->eh The MAC header. It is non-null for a layer2 | |||||
* packet, it is NULL for a layer-3 packet. | |||||
* **notyet** | |||||
* args->L3offset Offset in the packet to the L3 (IP or equiv.) header. | |||||
* | |||||
* m | args->m Pointer to the mbuf, as received from the caller. | * m | args->m Pointer to the mbuf, as received from the caller. | ||||
* It may change if ipfw_chk() does an m_pullup, or if it | * It may change if ipfw_chk() does an m_pullup, or if it | ||||
* consumes the packet because it calls send_reject(). | * consumes the packet because it calls send_reject(). | ||||
* XXX This has to change, so that ipfw_chk() never modifies | * XXX This has to change, so that ipfw_chk() never modifies | ||||
* or consumes the buffer. | * or consumes the buffer. | ||||
* ip is the beginning of the ip(4 or 6) header. | * OR | ||||
* Calculated by adding the L3offset to the start of data. | * args->mem Pointer to contigous memory chunk. | ||||
* (Until we start using L3offset, the packet is | * ip Is the beginning of the ip(4 or 6) header. | ||||
* supposed to start with the ip header). | * eh Ethernet header in case if input is Layer2. | ||||
*/ | */ | ||||
struct mbuf *m = args->m; | struct mbuf *m; | ||||
struct ip *ip = mtod(m, struct ip *); | struct ip *ip; | ||||
struct ether_header *eh; | |||||
/* | /* | ||||
* For rules which contain uid/gid or jail constraints, cache | * For rules which contain uid/gid or jail constraints, cache | ||||
* a copy of the users credentials after the pcb lookup has been | * a copy of the users credentials after the pcb lookup has been | ||||
* executed. This will speed up the processing of rules with | * executed. This will speed up the processing of rules with | ||||
* these types of constraints, as well as decrease contention | * these types of constraints, as well as decrease contention | ||||
* on pcb related locks. | * on pcb related locks. | ||||
*/ | */ | ||||
#ifndef __FreeBSD__ | #ifndef __FreeBSD__ | ||||
struct bsd_ucred ucred_cache; | struct bsd_ucred ucred_cache; | ||||
#else | #else | ||||
struct ucred *ucred_cache = NULL; | struct ucred *ucred_cache = NULL; | ||||
#endif | #endif | ||||
int ucred_lookup = 0; | int ucred_lookup = 0; | ||||
/* | |||||
* oif | args->oif If NULL, ipfw_chk has been called on the | |||||
* inbound path (ether_input, ip_input). | |||||
* If non-NULL, ipfw_chk has been called on the outbound path | |||||
* (ether_output, ip_output). | |||||
*/ | |||||
struct ifnet *oif = args->oif; | |||||
int f_pos = 0; /* index of current rule in the array */ | int f_pos = 0; /* index of current rule in the array */ | ||||
int retval = 0; | int retval = 0; | ||||
struct ifnet *oif, *iif; | |||||
/* | /* | ||||
* hlen The length of the IP header. | * hlen The length of the IP header. | ||||
*/ | */ | ||||
u_int hlen = 0; /* hlen >0 means we have an IP pkt */ | u_int hlen = 0; /* hlen >0 means we have an IP pkt */ | ||||
/* | /* | ||||
* offset The offset of a fragment. offset != 0 means that | * offset The offset of a fragment. offset != 0 means that | ||||
Show All 23 Lines | #endif | ||||
* src_ip, dst_ip ip addresses, in NETWORK format. | * src_ip, dst_ip ip addresses, in NETWORK format. | ||||
* Only valid for IPv4 packets. | * Only valid for IPv4 packets. | ||||
*/ | */ | ||||
uint8_t proto; | uint8_t proto; | ||||
uint16_t src_port, dst_port; /* NOTE: host format */ | uint16_t src_port, dst_port; /* NOTE: host format */ | ||||
struct in_addr src_ip, dst_ip; /* NOTE: network format */ | struct in_addr src_ip, dst_ip; /* NOTE: network format */ | ||||
int iplen = 0; | int iplen = 0; | ||||
int pktlen; | int pktlen; | ||||
uint16_t etype; /* Host order stored ether type */ | |||||
struct ipfw_dyn_info dyn_info; | struct ipfw_dyn_info dyn_info; | ||||
struct ip_fw *q = NULL; | struct ip_fw *q = NULL; | ||||
struct ip_fw_chain *chain = &V_layer3_chain; | struct ip_fw_chain *chain = &V_layer3_chain; | ||||
/* | /* | ||||
* We store in ulp a pointer to the upper layer protocol header. | * We store in ulp a pointer to the upper layer protocol header. | ||||
* In the ipv4 case this is easy to determine from the header, | * In the ipv4 case this is easy to determine from the header, | ||||
* but for ipv6 we might have some additional headers in the middle. | * but for ipv6 we might have some additional headers in the middle. | ||||
* ulp is NULL if not found. | * ulp is NULL if not found. | ||||
*/ | */ | ||||
void *ulp = NULL; /* upper layer protocol pointer. */ | void *ulp = NULL; /* upper layer protocol pointer. */ | ||||
/* XXX ipv6 variables */ | /* XXX ipv6 variables */ | ||||
int is_ipv6 = 0; | int is_ipv6 = 0; | ||||
uint8_t icmp6_type = 0; | uint8_t icmp6_type = 0; | ||||
uint16_t ext_hd = 0; /* bits vector for extension header filtering */ | uint16_t ext_hd = 0; /* bits vector for extension header filtering */ | ||||
/* end of ipv6 variables */ | /* end of ipv6 variables */ | ||||
int is_ipv4 = 0; | int is_ipv4 = 0; | ||||
int done = 0; /* flag to exit the outer loop */ | int done = 0; /* flag to exit the outer loop */ | ||||
IPFW_RLOCK_TRACKER; | IPFW_RLOCK_TRACKER; | ||||
bool mem; | |||||
if ((mem = (args->flags & IPFW_ARGS_LENMASK))) { | |||||
if (args->flags & IPFW_ARGS_ETHER) { | |||||
ae: Is it expected that ipfw_chk() will always get from pfil ethernet frame without VLAN tags? | |||||
Done Inline ActionsThat's a great question! Is that responsibility of a driver or of a packet filter. We will ponder on that. glebius: That's a great question! Is that responsibility of a driver or of a packet filter. We will… | |||||
eh = (struct ether_header *)args->mem; | |||||
if (eh->ether_type == htons(ETHERTYPE_VLAN)) | |||||
ip = (struct ip *) | |||||
((struct ether_vlan_header *)eh + 1); | |||||
else | |||||
ip = (struct ip *)(eh + 1); | |||||
} else { | |||||
eh = NULL; | |||||
ip = (struct ip *)args->mem; | |||||
} | |||||
pktlen = IPFW_ARGS_LENGTH(args->flags); | |||||
args->f_id.fib = args->ifp->if_fib; /* best guess */ | |||||
} else { | |||||
m = args->m; | |||||
if (m->m_flags & M_SKIP_FIREWALL || (! V_ipfw_vnet_ready)) | if (m->m_flags & M_SKIP_FIREWALL || (! V_ipfw_vnet_ready)) | ||||
return (IP_FW_PASS); /* accept */ | return (IP_FW_PASS); /* accept */ | ||||
if (args->flags & IPFW_ARGS_ETHER) { | |||||
/* We need some amount of data to be contiguous. */ | |||||
if (m->m_len < min(m->m_pkthdr.len, max_protohdr) && | |||||
(args->m = m = m_pullup(m, min(m->m_pkthdr.len, | |||||
max_protohdr))) == NULL) | |||||
goto pullup_failed; | |||||
eh = mtod(m, struct ether_header *); | |||||
ip = (struct ip *)(eh + 1); | |||||
} else { | |||||
eh = NULL; | |||||
ip = mtod(m, struct ip *); | |||||
} | |||||
pktlen = m->m_pkthdr.len; | |||||
args->f_id.fib = M_GETFIB(m); /* mbuf not altered */ | |||||
} | |||||
dst_ip.s_addr = 0; /* make sure it is initialized */ | dst_ip.s_addr = 0; /* make sure it is initialized */ | ||||
src_ip.s_addr = 0; /* make sure it is initialized */ | src_ip.s_addr = 0; /* make sure it is initialized */ | ||||
src_port = dst_port = 0; | src_port = dst_port = 0; | ||||
pktlen = m->m_pkthdr.len; | |||||
DYN_INFO_INIT(&dyn_info); | DYN_INFO_INIT(&dyn_info); | ||||
/* | /* | ||||
* PULLUP_TO(len, p, T) makes sure that len + sizeof(T) is contiguous, | * PULLUP_TO(len, p, T) makes sure that len + sizeof(T) is contiguous, | ||||
* then it sets p to point at the offset "len" in the mbuf. WARNING: the | * then it sets p to point at the offset "len" in the mbuf. WARNING: the | ||||
* pointer might become stale after other pullups (but we never use it | * pointer might become stale after other pullups (but we never use it | ||||
* this way). | * this way). | ||||
*/ | */ | ||||
#define PULLUP_TO(_len, p, T) PULLUP_LEN(_len, p, sizeof(T)) | #define PULLUP_TO(_len, p, T) PULLUP_LEN(_len, p, sizeof(T)) | ||||
#define EHLEN (eh != NULL ? ((char *)ip - (char *)eh) : 0) | |||||
Done Inline ActionsIt seems you forgot about ETHER_VLAN_ENCAP_LEN :-) ae: It seems you forgot about ETHER_VLAN_ENCAP_LEN :-)
I think you can use difference between eh… | |||||
#define PULLUP_LEN(_len, p, T) \ | #define PULLUP_LEN(_len, p, T) \ | ||||
do { \ | do { \ | ||||
int x = (_len) + T; \ | int x = (_len) + T + EHLEN; \ | ||||
if ((m)->m_len < x) { \ | if (mem) { \ | ||||
MPASS(pktlen >= x); \ | |||||
p = (char *)args->mem + (_len) + EHLEN; \ | |||||
} else { \ | |||||
if (__predict_false((m)->m_len < x)) { \ | |||||
args->m = m = m_pullup(m, x); \ | args->m = m = m_pullup(m, x); \ | ||||
if (m == NULL) \ | if (m == NULL) \ | ||||
goto pullup_failed; \ | goto pullup_failed; \ | ||||
} \ | } \ | ||||
p = (mtod(m, char *) + (_len)); \ | p = mtod(m, char *) + (_len) + EHLEN; \ | ||||
} \ | |||||
} while (0) | } while (0) | ||||
/* | /* | ||||
* if we have an ether header, | * In case pointers got stale after pullups, update them. | ||||
*/ | */ | ||||
if (args->flags & IPFW_ARGS_ETHER) | #define UPDATE_POINTERS() \ | ||||
etype = ntohs(args->eh->ether_type); | do { \ | ||||
else | if (!mem) { \ | ||||
etype = 0; | if (eh != NULL) { \ | ||||
eh = mtod(m, struct ether_header *); \ | |||||
ip = (struct ip *)(eh + 1); \ | |||||
} else \ | |||||
ip = mtod(m, struct ip *); \ | |||||
args->m = m; \ | |||||
} \ | |||||
} while (0) | |||||
/* Identify IP packets and fill up variables. */ | /* Identify IP packets and fill up variables. */ | ||||
if (pktlen >= sizeof(struct ip6_hdr) && | if (pktlen >= sizeof(struct ip6_hdr) && | ||||
(etype == 0 || etype == ETHERTYPE_IPV6) && ip->ip_v == 6) { | (eh == NULL || eh->ether_type == htons(ETHERTYPE_IPV6)) && | ||||
ip->ip_v == 6) { | |||||
struct ip6_hdr *ip6 = (struct ip6_hdr *)ip; | struct ip6_hdr *ip6 = (struct ip6_hdr *)ip; | ||||
is_ipv6 = 1; | is_ipv6 = 1; | ||||
args->flags |= IPFW_ARGS_IP6; | |||||
hlen = sizeof(struct ip6_hdr); | hlen = sizeof(struct ip6_hdr); | ||||
proto = ip6->ip6_nxt; | proto = ip6->ip6_nxt; | ||||
/* Search extension headers to find upper layer protocols */ | /* Search extension headers to find upper layer protocols */ | ||||
while (ulp == NULL && offset == 0) { | while (ulp == NULL && offset == 0) { | ||||
switch (proto) { | switch (proto) { | ||||
case IPPROTO_ICMPV6: | case IPPROTO_ICMPV6: | ||||
PULLUP_TO(hlen, ulp, struct icmp6_hdr); | PULLUP_TO(hlen, ulp, struct icmp6_hdr); | ||||
icmp6_type = ICMP6(ulp)->icmp6_type; | icmp6_type = ICMP6(ulp)->icmp6_type; | ||||
▲ Show 20 Lines • Show All 156 Lines • ▼ Show 20 Lines | while (ulp == NULL && offset == 0) { | ||||
"Extension Header(%d), ext_hd=%x\n", | "Extension Header(%d), ext_hd=%x\n", | ||||
proto, ext_hd); | proto, ext_hd); | ||||
if (V_fw_deny_unknown_exthdrs) | if (V_fw_deny_unknown_exthdrs) | ||||
return (IP_FW_DENY); | return (IP_FW_DENY); | ||||
PULLUP_TO(hlen, ulp, struct ip6_ext); | PULLUP_TO(hlen, ulp, struct ip6_ext); | ||||
break; | break; | ||||
} /*switch */ | } /*switch */ | ||||
} | } | ||||
ip = mtod(m, struct ip *); | UPDATE_POINTERS(); | ||||
ip6 = (struct ip6_hdr *)ip; | ip6 = (struct ip6_hdr *)ip; | ||||
args->f_id.addr_type = 6; | args->f_id.addr_type = 6; | ||||
args->f_id.src_ip6 = ip6->ip6_src; | args->f_id.src_ip6 = ip6->ip6_src; | ||||
args->f_id.dst_ip6 = ip6->ip6_dst; | args->f_id.dst_ip6 = ip6->ip6_dst; | ||||
args->f_id.flow_id6 = ntohl(ip6->ip6_flow); | args->f_id.flow_id6 = ntohl(ip6->ip6_flow); | ||||
iplen = ntohs(ip6->ip6_plen) + sizeof(*ip6); | iplen = ntohs(ip6->ip6_plen) + sizeof(*ip6); | ||||
} else if (pktlen >= sizeof(struct ip) && | } else if (pktlen >= sizeof(struct ip) && | ||||
(etype == 0 || etype == ETHERTYPE_IP) && ip->ip_v == 4) { | (eh == NULL || eh->ether_type == htons(ETHERTYPE_IP)) && | ||||
ip->ip_v == 4) { | |||||
is_ipv4 = 1; | is_ipv4 = 1; | ||||
args->flags |= IPFW_ARGS_IP4; | |||||
hlen = ip->ip_hl << 2; | hlen = ip->ip_hl << 2; | ||||
/* | /* | ||||
* Collect parameters into local variables for faster | * Collect parameters into local variables for faster | ||||
* matching. | * matching. | ||||
*/ | */ | ||||
proto = ip->ip_p; | proto = ip->ip_p; | ||||
src_ip = ip->ip_src; | src_ip = ip->ip_src; | ||||
dst_ip = ip->ip_dst; | dst_ip = ip->ip_dst; | ||||
Show All 39 Lines | if (offset == 0) { | ||||
//args->f_id.flags = ICMP(ulp)->icmp_type; | //args->f_id.flags = ICMP(ulp)->icmp_type; | ||||
break; | break; | ||||
default: | default: | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
ip = mtod(m, struct ip *); | UPDATE_POINTERS(); | ||||
args->f_id.addr_type = 4; | args->f_id.addr_type = 4; | ||||
args->f_id.src_ip = ntohl(src_ip.s_addr); | args->f_id.src_ip = ntohl(src_ip.s_addr); | ||||
args->f_id.dst_ip = ntohl(dst_ip.s_addr); | args->f_id.dst_ip = ntohl(dst_ip.s_addr); | ||||
} else { | } else { | ||||
proto = 0; | proto = 0; | ||||
dst_ip.s_addr = src_ip.s_addr = 0; | dst_ip.s_addr = src_ip.s_addr = 0; | ||||
args->f_id.addr_type = 1; /* XXX */ | args->f_id.addr_type = 1; /* XXX */ | ||||
} | } | ||||
#undef PULLUP_TO | #undef PULLUP_TO | ||||
pktlen = iplen < pktlen ? iplen: pktlen; | pktlen = iplen < pktlen ? iplen: pktlen; | ||||
/* Properly initialize the rest of f_id */ | /* Properly initialize the rest of f_id */ | ||||
args->f_id.proto = proto; | args->f_id.proto = proto; | ||||
args->f_id.src_port = src_port = ntohs(src_port); | args->f_id.src_port = src_port = ntohs(src_port); | ||||
args->f_id.dst_port = dst_port = ntohs(dst_port); | args->f_id.dst_port = dst_port = ntohs(dst_port); | ||||
args->f_id.fib = M_GETFIB(m); | |||||
IPFW_PF_RLOCK(chain); | IPFW_PF_RLOCK(chain); | ||||
if (! V_ipfw_vnet_ready) { /* shutting down, leave NOW. */ | if (! V_ipfw_vnet_ready) { /* shutting down, leave NOW. */ | ||||
IPFW_PF_RUNLOCK(chain); | IPFW_PF_RUNLOCK(chain); | ||||
return (IP_FW_PASS); /* accept */ | return (IP_FW_PASS); /* accept */ | ||||
} | } | ||||
if (args->flags & IPFW_ARGS_REF) { | if (args->flags & IPFW_ARGS_REF) { | ||||
/* | /* | ||||
* Packet has already been tagged as a result of a previous | * Packet has already been tagged as a result of a previous | ||||
* match on rule args->rule aka args->rule_id (PIPE, QUEUE, | * match on rule args->rule aka args->rule_id (PIPE, QUEUE, | ||||
* REASS, NETGRAPH, DIVERT/TEE...) | * REASS, NETGRAPH, DIVERT/TEE...) | ||||
* Validate the slot and continue from the next one | * Validate the slot and continue from the next one | ||||
* if still present, otherwise do a lookup. | * if still present, otherwise do a lookup. | ||||
*/ | */ | ||||
f_pos = (args->rule.chain_id == chain->id) ? | f_pos = (args->rule.chain_id == chain->id) ? | ||||
args->rule.slot : | args->rule.slot : | ||||
ipfw_find_rule(chain, args->rule.rulenum, | ipfw_find_rule(chain, args->rule.rulenum, | ||||
args->rule.rule_id); | args->rule.rule_id); | ||||
} else { | } else { | ||||
f_pos = 0; | f_pos = 0; | ||||
} | } | ||||
if (args->flags & IPFW_ARGS_IN) { | |||||
iif = args->ifp; | |||||
oif = NULL; | |||||
} else { | |||||
MPASS(args->flags & IPFW_ARGS_OUT); | |||||
iif = mem ? NULL : m->m_pkthdr.rcvif; | |||||
Not Done Inline ActionsThis probably can break something. mbuf can have initialized oif and m_pkthdr.rcvif in the same time, this happens when we are processing forwarded packet. ae: This probably can break something. mbuf can have initialized oif and m_pkthdr.rcvif in the same… | |||||
Not Done Inline ActionsIs it possible to construct a rule that would match on oif and iif at the same time? glebius: Is it possible to construct a rule that would match on oif and iif at the same time? | |||||
Not Done Inline ActionsNot only possible, in use. You can make decisions about a packet exiting based on if it arrived via a specific if. rgrimes: Not only possible, in use. You can make decisions about a packet exiting based on if it… | |||||
Done Inline ActionsThis particular syntax won't match anything, since "via" always uses either of two interfaces. Also, a rule having "in" and "out" at the same time shoudn't match as well. However, this rule correctly matches on two interfaces indeed: ipfw add allow ip from any to any recv em0 out xmit em1 "out" is optional here. So, something needs to be fixed with my patch. glebius: This particular syntax won't match anything, since "via" always uses either of two interfaces. | |||||
oif = args->ifp; | |||||
} | |||||
/* | /* | ||||
* Now scan the rules, and parse microinstructions for each rule. | * Now scan the rules, and parse microinstructions for each rule. | ||||
* We have two nested loops and an inner switch. Sometimes we | * We have two nested loops and an inner switch. Sometimes we | ||||
* need to break out of one or both loops, or re-enter one of | * need to break out of one or both loops, or re-enter one of | ||||
* the loops with updated variables. Loop variables are: | * the loops with updated variables. Loop variables are: | ||||
* | * | ||||
* f_pos (outer loop) points to the current rule. | * f_pos (outer loop) points to the current rule. | ||||
* On output it points to the matching rule. | * On output it points to the matching rule. | ||||
▲ Show 20 Lines • Show All 80 Lines • ▼ Show 20 Lines | |||||
#ifdef __FreeBSD__ | #ifdef __FreeBSD__ | ||||
&ucred_cache); | &ucred_cache); | ||||
#else | #else | ||||
(void *)&ucred_cache); | (void *)&ucred_cache); | ||||
#endif | #endif | ||||
break; | break; | ||||
case O_RECV: | case O_RECV: | ||||
match = iface_match(m->m_pkthdr.rcvif, | match = iface_match(iif, (ipfw_insn_if *)cmd, | ||||
(ipfw_insn_if *)cmd, chain, &tablearg); | chain, &tablearg); | ||||
break; | break; | ||||
case O_XMIT: | case O_XMIT: | ||||
match = iface_match(oif, (ipfw_insn_if *)cmd, | match = iface_match(oif, (ipfw_insn_if *)cmd, | ||||
chain, &tablearg); | chain, &tablearg); | ||||
break; | break; | ||||
case O_VIA: | case O_VIA: | ||||
match = iface_match(oif ? oif : | match = iface_match(args->ifp, | ||||
m->m_pkthdr.rcvif, (ipfw_insn_if *)cmd, | (ipfw_insn_if *)cmd, chain, &tablearg); | ||||
chain, &tablearg); | |||||
break; | break; | ||||
case O_MACADDR2: | case O_MACADDR2: | ||||
if (args->flags & IPFW_ARGS_ETHER) { | if (args->flags & IPFW_ARGS_ETHER) { | ||||
u_int32_t *want = (u_int32_t *) | u_int32_t *want = (u_int32_t *) | ||||
((ipfw_insn_mac *)cmd)->addr; | ((ipfw_insn_mac *)cmd)->addr; | ||||
u_int32_t *mask = (u_int32_t *) | u_int32_t *mask = (u_int32_t *) | ||||
((ipfw_insn_mac *)cmd)->mask; | ((ipfw_insn_mac *)cmd)->mask; | ||||
u_int32_t *hdr = (u_int32_t *)args->eh; | u_int32_t *hdr = (u_int32_t *)eh; | ||||
match = | match = | ||||
( want[0] == (hdr[0] & mask[0]) && | ( want[0] == (hdr[0] & mask[0]) && | ||||
want[1] == (hdr[1] & mask[1]) && | want[1] == (hdr[1] & mask[1]) && | ||||
want[2] == (hdr[2] & mask[2]) ); | want[2] == (hdr[2] & mask[2]) ); | ||||
} | } | ||||
break; | break; | ||||
case O_MAC_TYPE: | case O_MAC_TYPE: | ||||
if (args->flags & IPFW_ARGS_ETHER) { | if (args->flags & IPFW_ARGS_ETHER) { | ||||
u_int16_t *p = | u_int16_t *p = | ||||
((ipfw_insn_u16 *)cmd)->ports; | ((ipfw_insn_u16 *)cmd)->ports; | ||||
int i; | int i; | ||||
for (i = cmdlen - 1; !match && i>0; | for (i = cmdlen - 1; !match && i>0; | ||||
i--, p += 2) | i--, p += 2) | ||||
match = (etype >= p[0] && | match = | ||||
etype <= p[1]); | (ntohs(eh->ether_type) >= | ||||
p[0] && | |||||
ntohs(eh->ether_type) <= | |||||
p[1]); | |||||
} | } | ||||
break; | break; | ||||
case O_FRAG: | case O_FRAG: | ||||
match = (offset != 0); | match = (offset != 0); | ||||
break; | break; | ||||
case O_IN: /* "out" is "not in" */ | case O_IN: /* "out" is "not in" */ | ||||
▲ Show 20 Lines • Show All 457 Lines • ▼ Show 20 Lines | #endif /* INET6 */ | ||||
m_tag_prepend(m, mtag); | m_tag_prepend(m, mtag); | ||||
at = (struct pf_mtag *)(mtag + 1); | at = (struct pf_mtag *)(mtag + 1); | ||||
at->qid = altq->qid; | at->qid = altq->qid; | ||||
at->hdr = ip; | at->hdr = ip; | ||||
break; | break; | ||||
} | } | ||||
case O_LOG: | case O_LOG: | ||||
ipfw_log(chain, f, hlen, args, m, | ipfw_log(chain, f, hlen, args, | ||||
oif, offset | ip6f_mf, tablearg, ip); | offset | ip6f_mf, tablearg, ip); | ||||
match = 1; | match = 1; | ||||
break; | break; | ||||
case O_PROB: | case O_PROB: | ||||
match = (random()<((ipfw_insn_u32 *)cmd)->d[0]); | match = (random()<((ipfw_insn_u32 *)cmd)->d[0]); | ||||
break; | break; | ||||
case O_VERREVPATH: | case O_VERREVPATH: | ||||
/* Outgoing packets automatically pass/match */ | /* Outgoing packets automatically pass/match */ | ||||
match = ((oif != NULL) || | match = (args->flags & IPFW_ARGS_OUT || | ||||
(m->m_pkthdr.rcvif == NULL) || | |||||
( | ( | ||||
#ifdef INET6 | #ifdef INET6 | ||||
is_ipv6 ? | is_ipv6 ? | ||||
verify_path6(&(args->f_id.src_ip6), | verify_path6(&(args->f_id.src_ip6), | ||||
m->m_pkthdr.rcvif, args->f_id.fib) : | iif, args->f_id.fib) : | ||||
#endif | #endif | ||||
verify_path(src_ip, m->m_pkthdr.rcvif, | verify_path(src_ip, iif, args->f_id.fib))); | ||||
args->f_id.fib))); | |||||
break; | break; | ||||
case O_VERSRCREACH: | case O_VERSRCREACH: | ||||
/* Outgoing packets automatically pass/match */ | /* Outgoing packets automatically pass/match */ | ||||
match = (hlen > 0 && ((oif != NULL) || ( | match = (hlen > 0 && ((oif != NULL) || ( | ||||
#ifdef INET6 | #ifdef INET6 | ||||
is_ipv6 ? | is_ipv6 ? | ||||
verify_path6(&(args->f_id.src_ip6), | verify_path6(&(args->f_id.src_ip6), | ||||
Show All 9 Lines | |||||
#ifdef INET6 | #ifdef INET6 | ||||
|| (is_ipv6 && | || (is_ipv6 && | ||||
in6_localaddr(&(args->f_id.src_ip6))) | in6_localaddr(&(args->f_id.src_ip6))) | ||||
#endif | #endif | ||||
)) | )) | ||||
match = | match = | ||||
#ifdef INET6 | #ifdef INET6 | ||||
is_ipv6 ? verify_path6( | is_ipv6 ? verify_path6( | ||||
&(args->f_id.src_ip6), | &(args->f_id.src_ip6), iif, | ||||
m->m_pkthdr.rcvif, | |||||
args->f_id.fib) : | args->f_id.fib) : | ||||
#endif | #endif | ||||
verify_path(src_ip, | verify_path(src_ip, iif, | ||||
m->m_pkthdr.rcvif, | |||||
args->f_id.fib); | args->f_id.fib); | ||||
else | else | ||||
match = 1; | match = 1; | ||||
break; | break; | ||||
case O_IPSEC: | case O_IPSEC: | ||||
match = (m_tag_find(m, | match = (m_tag_find(m, | ||||
PACKET_TAG_IPSEC_IN_DONE, NULL) != NULL); | PACKET_TAG_IPSEC_IN_DONE, NULL) != NULL); | ||||
▲ Show 20 Lines • Show All 1,058 Lines • Show Last 20 Lines |
Is it expected that ipfw_chk() will always get from pfil ethernet frame without VLAN tags?