/*
- * Copyright (c) 2007-2015 Apple Inc. All rights reserved.
+ * Copyright (c) 2007-2016 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
#endif /* DUMMYNET */
/*
- * For RandomULong(), to get a 32 bits random value
+ * For RandomULong(), to get a 32 bits random value
* Note that random() returns a 31 bits value, see rdar://11159750
*/
#include <dev/random/randomdev.h>
void *, struct pf_pdesc *, struct pf_rule **,
struct pf_ruleset **, struct ifqueue *);
#if DUMMYNET
-static int pf_test_dummynet(struct pf_rule **, int,
- struct pfi_kif *, struct mbuf **,
+static int pf_test_dummynet(struct pf_rule **, int,
+ struct pfi_kif *, struct mbuf **,
struct pf_pdesc *, struct ip_fw_args *);
#endif /* DUMMYNET */
static int pf_test_fragment(struct pf_rule **, int,
#endif
static const size_t PF_PPTP_CTRL_MSG_MINSIZE =
- sizeof (struct pf_pptp_hdr) +
- sizeof (struct pf_pptp_ctrl_hdr) +
- MIN(sizeof (struct pf_pptp_ctrl_start_req),
- MIN(sizeof (struct pf_pptp_ctrl_start_rpy),
- MIN(sizeof (struct pf_pptp_ctrl_stop_req),
- MIN(sizeof (struct pf_pptp_ctrl_stop_rpy),
- MIN(sizeof (struct pf_pptp_ctrl_echo_req),
- MIN(sizeof (struct pf_pptp_ctrl_echo_rpy),
- MIN(sizeof (struct pf_pptp_ctrl_call_out_req),
- MIN(sizeof (struct pf_pptp_ctrl_call_out_rpy),
- MIN(sizeof (struct pf_pptp_ctrl_call_in_1st),
- MIN(sizeof (struct pf_pptp_ctrl_call_in_2nd),
- MIN(sizeof (struct pf_pptp_ctrl_call_in_3rd),
- MIN(sizeof (struct pf_pptp_ctrl_call_clr),
- MIN(sizeof (struct pf_pptp_ctrl_call_disc),
- MIN(sizeof (struct pf_pptp_ctrl_error),
- sizeof (struct pf_pptp_ctrl_set_linkinfo)
- ))))))))))))));
+ sizeof (struct pf_pptp_hdr) + sizeof (struct pf_pptp_ctrl_hdr);
union pf_pptp_ctrl_msg_union {
struct pf_pptp_ctrl_start_req start_req;
return (rm);
}
-/*
+/*
* Get address translation information for NAT/BINAT/RDR
* pd : pf packet descriptor
* m : mbuf holding the packet
{
struct pf_addr *saddr, *daddr;
u_int16_t sport, dport;
- struct inpcbinfo *pi;
+ struct inpcbinfo *pi;
int inp = 0;
if (pd == NULL)
#else
if (inp == 0) {
inp = in_pcblookup_hash_exists(pi, saddr->v4, sport,
- daddr->v4, dport, INPLOOKUP_WILDCARD,
+ daddr->v4, dport, INPLOOKUP_WILDCARD,
&pd->lookup.uid, &pd->lookup.gid, NULL);
if (inp == 0)
return (-1);
}
break;
#endif /* INET6 */
-
+
default:
return (-1);
}
int moff, hlen = sizeof(*ip4);
if ((mp = m_pulldown(m, hlen, ICMP_MINLEN, &moff)) == NULL)
- return (PF_NAT64);
+ return (PF_DROP);
icmp = (struct icmp *)(void *)(mtod(mp, char *) + moff);
icmp->icmp_cksum = 0;
int moff, hlen = sizeof(*ip6);
if ((mp = m_pulldown(m, hlen, sizeof(*icmp6), &moff)) == NULL)
- return (PF_NAT64);
+ return (PF_DROP);
icmp6 = (struct icmp6_hdr *)(void *)(mtod(mp, char *) + moff);
icmp6->icmp6_cksum = 0;
icmp6->icmp6_cksum = inet6_cksum(m, IPPROTO_ICMPV6, hlen,
ntohs(ip6->ip6_plen));
+ } else if (pd->proto == IPPROTO_UDP) {
+ struct mbuf *mp;
+ struct udphdr *uh;
+ int moff, hlen = sizeof(*ip6);
+ if ((mp = m_pulldown(m, hlen, sizeof(*uh), &moff)) == NULL)
+ return (PF_DROP);
+ uh = (struct udphdr *)(void *)(mtod(mp, char *) + moff);
+ if (uh->uh_sum == 0)
+ uh->uh_sum = inet6_cksum(m, IPPROTO_UDP, hlen,
+ ntohs(ip6->ip6_plen));
}
+
ip6_input(m);
return (PF_NAT64);
}
(r->flagset & th->th_flags) != r->flags)
r = TAILQ_NEXT(r, entries);
/* tcp/udp only. uid.op always 0 in other cases */
- else if (r->uid.op && (pd->lookup.done || (pd->lookup.done =
- pf_socket_lookup(direction, pd), 1)) &&
+ else if (r->uid.op && (pd->lookup.done || ((void)(pd->lookup.done =
+ pf_socket_lookup(direction, pd)), 1)) &&
!pf_match_uid(r->uid.op, r->uid.uid[0], r->uid.uid[1],
pd->lookup.uid))
r = TAILQ_NEXT(r, entries);
/* tcp/udp only. gid.op always 0 in other cases */
- else if (r->gid.op && (pd->lookup.done || (pd->lookup.done =
- pf_socket_lookup(direction, pd), 1)) &&
+ else if (r->gid.op && (pd->lookup.done || ((void)(pd->lookup.done =
+ pf_socket_lookup(direction, pd)), 1)) &&
!pf_match_gid(r->gid.op, r->gid.gid[0], r->gid.gid[1],
pd->lookup.gid))
r = TAILQ_NEXT(r, entries);
#if DUMMYNET
/*
- * When pf_test_dummynet() returns PF_PASS, the rule matching parameter "rm"
+ * When pf_test_dummynet() returns PF_PASS, the rule matching parameter "rm"
* remains unchanged, meaning the packet did not match a dummynet rule.
- * when the packet does match a dummynet rule, pf_test_dummynet() returns
- * PF_PASS and zero out the mbuf rule as the packet is effectively siphoned
+ * when the packet does match a dummynet rule, pf_test_dummynet() returns
+ * PF_PASS and zero out the mbuf rule as the packet is effectively siphoned
* out by dummynet.
*/
static int
-pf_test_dummynet(struct pf_rule **rm, int direction, struct pfi_kif *kif,
+pf_test_dummynet(struct pf_rule **rm, int direction, struct pfi_kif *kif,
struct mbuf **m0, struct pf_pdesc *pd, struct ip_fw_args *fwa)
{
struct mbuf *m = *m0;
if (!DUMMYNET_LOADED)
return (PF_PASS);
-
+
if (TAILQ_EMPTY(pf_main_ruleset.rules[PF_RULESET_DUMMYNET].active.ptr))
return (PF_PASS);
-
+
bzero(&dnflow, sizeof(dnflow));
hdrlen = 0;
/* Fragments don't gave protocol headers */
- if (!(pd->flags & PFDESC_IP_FRAG))
+ if (!(pd->flags & PFDESC_IP_FRAG))
switch (pd->proto) {
case IPPROTO_TCP:
dnflow.fwa_id.flags = pd->hdr.tcp->th_flags;
r->src.neg, kif))
r = r->skip[PF_SKIP_SRC_ADDR].ptr;
/* tcp/udp only. port_op always 0 in other cases */
- else if (r->proto == pd->proto &&
+ else if (r->proto == pd->proto &&
(r->proto == IPPROTO_TCP || r->proto == IPPROTO_UDP) &&
((pd->flags & PFDESC_IP_FRAG) ||
((r->src.xport.range.op &&
th->th_dport)))
r = r->skip[PF_SKIP_DST_PORT].ptr;
/* icmp only. type always 0 in other cases */
- else if (r->type &&
+ else if (r->type &&
((pd->flags & PFDESC_IP_FRAG) ||
r->type != icmptype + 1))
r = TAILQ_NEXT(r, entries);
/* icmp only. type always 0 in other cases */
- else if (r->code &&
+ else if (r->code &&
((pd->flags & PFDESC_IP_FRAG) ||
r->code != icmpcode + 1))
r = TAILQ_NEXT(r, entries);
else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag))
r = TAILQ_NEXT(r, entries);
else {
- /*
- * Need to go past the previous dummynet matching rule
+ /*
+ * Need to go past the previous dummynet matching rule
*/
if (r->anchor == NULL) {
if (found_prev_rule) {
if (r->action == PF_NODUMMYNET) {
int dirndx = (direction == PF_OUT);
-
+
r->packets[dirndx]++;
r->bytes[dirndx] += pd->tot_len;
if (r->dnpipe && ip_dn_io_ptr != NULL) {
int dirndx = (direction == PF_OUT);
-
+
r->packets[dirndx]++;
r->bytes[dirndx] += pd->tot_len;
-
+
dnflow.fwa_cookie = r->dnpipe;
dnflow.fwa_pf_rule = r;
dnflow.fwa_id.proto = pd->proto;
dnflow.fwa_oif = fwa->fwa_oif;
dnflow.fwa_oflags = fwa->fwa_oflags;
/*
- * Note that fwa_ro, fwa_dst and fwa_ipoa are
- * actually in a union so the following does work
+ * Note that fwa_ro, fwa_dst and fwa_ipoa are
+ * actually in a union so the following does work
* for both IPv4 and IPv6
*/
dnflow.fwa_ro = fwa->fwa_ro;
dnflow.fwa_unfragpartlen = fwa->fwa_unfragpartlen;
dnflow.fwa_exthdrs = fwa->fwa_exthdrs;
}
-
+
if (af == AF_INET) {
struct ip *iphdr = mtod(m, struct ip *);
NTOHS(iphdr->ip_len);
NTOHS(iphdr->ip_off);
}
/*
- * Don't need to unlock pf_lock as NET_THREAD_HELD_PF
+ * Don't need to unlock pf_lock as NET_THREAD_HELD_PF
* allows for recursive behavior
*/
ip_dn_io_ptr(m,
dnflow.fwa_cookie,
- af == AF_INET ?
+ af == AF_INET ?
direction == PF_IN ? DN_TO_IP_IN : DN_TO_IP_OUT :
direction == PF_IN ? DN_TO_IP6_IN : DN_TO_IP6_OUT,
&dnflow, DN_CLIENT_PF);
-
+
/*
- * The packet is siphoned out by dummynet so return a NULL
+ * The packet is siphoned out by dummynet so return a NULL
* mbuf so the caller can still return success.
*/
*m0 = NULL;
-
+
return (PF_PASS);
}
struct tcphdr *th;
struct pf_pptp_state *pptps;
struct pf_pptp_ctrl_msg cm;
- size_t plen;
+ size_t plen, tlen;
struct pf_state *gs;
u_int16_t ct;
u_int16_t *pac_call_id;
plen = min(sizeof (cm), m->m_pkthdr.len - off);
if (plen < PF_PPTP_CTRL_MSG_MINSIZE)
return;
-
+ tlen = plen - PF_PPTP_CTRL_MSG_MINSIZE;
m_copydata(m, off, plen, &cm);
if (ntohl(cm.hdr.magic) != PF_PPTP_MAGIC_NUMBER)
if (ntohs(cm.hdr.type) != 1)
return;
+#define TYPE_LEN_CHECK(_type, _name) \
+ case PF_PPTP_CTRL_TYPE_##_type: \
+ if (tlen < sizeof(struct pf_pptp_ctrl_##_name)) \
+ return; \
+ break;
+
+ switch (cm.ctrl.type) {
+ TYPE_LEN_CHECK(START_REQ, start_req);
+ TYPE_LEN_CHECK(START_RPY, start_rpy);
+ TYPE_LEN_CHECK(STOP_REQ, stop_req);
+ TYPE_LEN_CHECK(STOP_RPY, stop_rpy);
+ TYPE_LEN_CHECK(ECHO_REQ, echo_req);
+ TYPE_LEN_CHECK(ECHO_RPY, echo_rpy);
+ TYPE_LEN_CHECK(CALL_OUT_REQ, call_out_req);
+ TYPE_LEN_CHECK(CALL_OUT_RPY, call_out_rpy);
+ TYPE_LEN_CHECK(CALL_IN_1ST, call_in_1st);
+ TYPE_LEN_CHECK(CALL_IN_2ND, call_in_2nd);
+ TYPE_LEN_CHECK(CALL_IN_3RD, call_in_3rd);
+ TYPE_LEN_CHECK(CALL_CLR, call_clr);
+ TYPE_LEN_CHECK(CALL_DISC, call_disc);
+ TYPE_LEN_CHECK(ERROR, error);
+ TYPE_LEN_CHECK(SET_LINKINFO, set_linkinfo);
+ default:
+ return;
+ }
+#undef TYPE_LEN_CHECK
+
if (!gs) {
gs = pool_get(&pf_state_pl, PR_WAITOK);
if (!gs)
}
return (PF_PASS);
- break;
}
case IPPROTO_UDP: {
struct udphdr uh;
}
return (PF_PASS);
- break;
}
#if INET
case IPPROTO_ICMP: {
}
return (PF_PASS);
- break;
}
#endif /* INET */
#if INET6
}
return (PF_PASS);
- break;
}
#endif /* INET6 */
default: {
}
return (PF_PASS);
- break;
}
}
}