--- sys/contrib/pf/net/pf.c 2013-02-15 18:13:56.000000000 +0100 +++ sys/contrib/pf/net/pf.c 2013-02-19 16:25:25.000000000 +0100 @@ -261,7 +261,8 @@ const struct pf_addr *, const struct pf_addr *, u_int16_t, u_int16_t, u_int32_t, u_int32_t, u_int8_t, u_int16_t, u_int16_t, u_int8_t, int, - u_int16_t, struct ether_header *, struct ifnet *); + u_int16_t, struct ether_header *, struct ifnet *, + struct route *route_to_ro); static void pf_send_icmp(struct mbuf *, u_int8_t, u_int8_t, sa_family_t, struct pf_rule *); void pf_detach_state(struct pf_state *); @@ -1570,7 +1571,7 @@ cur->key[PF_SK_WIRE]->port[1], cur->key[PF_SK_WIRE]->port[0], cur->src.seqhi, cur->src.seqlo + 1, - TH_RST|TH_ACK, 0, 0, 0, 1, cur->tag, NULL, NULL); + TH_RST|TH_ACK, 0, 0, 0, 1, cur->tag, NULL, NULL, NULL); } #ifdef __FreeBSD__ RB_REMOVE(pf_state_tree_id, &V_tree_id, cur); @@ -2265,7 +2266,7 @@ const struct pf_addr *saddr, const struct pf_addr *daddr, u_int16_t sport, u_int16_t dport, u_int32_t seq, u_int32_t ack, u_int8_t flags, u_int16_t win, u_int16_t mss, u_int8_t ttl, int tag, - u_int16_t rtag, struct ether_header *eh, struct ifnet *ifp) + u_int16_t rtag, struct ether_header *eh, struct ifnet *ifp, struct route *route_to_ro) { struct mbuf *m; int len, tlen; @@ -2442,11 +2443,11 @@ if (eh == NULL) { #ifdef __FreeBSD__ PF_UNLOCK(); - ip_output(m, (void *)NULL, (void *)NULL, 0, + ip_output(m, (void *)NULL, route_to_ro, 0, (void *)NULL, (void *)NULL); PF_LOCK(); #else /* ! __FreeBSD__ */ - ip_output(m, (void *)NULL, (void *)NULL, 0, + ip_output(m, (void *)NULL, route_to_ro, 0, (void *)NULL, (void *)NULL); #endif } else { @@ -3681,7 +3682,7 @@ #endif pd->src, th->th_dport, th->th_sport, ntohl(th->th_ack), ack, TH_RST|TH_ACK, 0, 0, - r->return_ttl, 1, 0, pd->eh, kif->pfik_ifp); + r->return_ttl, 1, 0, pd->eh, kif->pfik_ifp, NULL); } } else if (pd->proto != IPPROTO_ICMP && af == AF_INET && r->return_icmp) @@ -3990,7 +3991,7 @@ pf_send_tcp(r, pd->af, pd->dst, pd->src, th->th_dport, #endif th->th_sport, s->src.seqhi, ntohl(th->th_seq) + 1, - TH_SYN|TH_ACK, 0, s->src.mss, 0, 1, 0, NULL, NULL); + TH_SYN|TH_ACK, 0, s->src.mss, 0, 1, 0, NULL, NULL, NULL); REASON_SET(&reason, PFRES_SYNPROXY); return (PF_SYNPROXY_DROP); } @@ -4445,7 +4446,7 @@ th->th_sport, ntohl(th->th_ack), 0, TH_RST, 0, 0, (*state)->rule.ptr->return_ttl, 1, 0, - pd->eh, kif->pfik_ifp); + pd->eh, kif->pfik_ifp, NULL); src->seqlo = 0; src->seqhi = 1; src->max_win = 1; @@ -4566,6 +4567,12 @@ struct pf_state_peer *src, *dst; struct pf_state_key *sk; + /* A route information is required for route-to and synproxy state combination. */ + struct route route_to_ro; + struct rtentry route_to_rt; + struct sockaddr_in route_to_gw; + struct route *route_to_ro0 = NULL; + key.af = pd->af; key.proto = IPPROTO_TCP; if (direction == PF_IN) { /* wire side, straight */ @@ -4614,7 +4621,7 @@ pd->src, th->th_dport, th->th_sport, (*state)->src.seqhi, ntohl(th->th_seq) + 1, TH_SYN|TH_ACK, 0, (*state)->src.mss, 0, 1, - 0, NULL, NULL); + 0, NULL, NULL, NULL); REASON_SET(reason, PFRES_SYNPROXY); return (PF_SYNPROXY_DROP); } else if (!(th->th_flags & TH_ACK) || @@ -4630,6 +4637,33 @@ (*state)->src.state = PF_TCPS_PROXY_DST; } if ((*state)->src.state == PF_TCPS_PROXY_DST) { + /* When running a combination of route-to and synproxy state, + the SYN packet going to route-to target must use the target interface + and gateway stored in connection state instead of standard route table lookup */ + if ( (*state)->rt_kif ) { + /* Assign gateway interface and flags */ + route_to_rt.rt_flags = RTF_UP|RTF_HOST|RTF_GATEWAY; + route_to_rt.rt_ifp = (*state)->rt_kif->pfik_ifp; + route_to_rt.rt_ifa = (*state)->rt_kif->pfik_ifp->if_addr; + route_to_rt.rt_rmx.rmx_mtu = (*state)->rt_kif->pfik_ifp->if_mtu; + + /* Assign gateway address. */ + route_to_gw.sin_family = AF_INET; + route_to_gw.sin_len = sizeof(struct sockaddr_in); + route_to_gw.sin_addr = (*state)->rt_addr.v4; + + /* Assign destination address. */ + ((struct sockaddr_in*)&route_to_ro.ro_dst)->sin_family = AF_INET; + ((struct sockaddr_in*)&route_to_ro.ro_dst)->sin_len = sizeof(struct sockaddr_in); + ((struct sockaddr_in*)&route_to_ro.ro_dst)->sin_addr = sk->addr[pd->didx].v4; + + /* Glue things together */ + route_to_ro.ro_lle = NULL; + route_to_rt.rt_gateway = (struct sockaddr*)&route_to_gw; + route_to_ro.ro_rt = &route_to_rt; + route_to_ro0 = &route_to_ro; + } + if (direction == (*state)->direction) { if (((th->th_flags & (TH_SYN|TH_ACK)) != TH_ACK) || (ntohl(th->th_ack) != (*state)->src.seqhi + 1) || @@ -4648,7 +4682,7 @@ &sk->addr[pd->sidx], &sk->addr[pd->didx], sk->port[pd->sidx], sk->port[pd->didx], (*state)->dst.seqhi, 0, TH_SYN, 0, - (*state)->src.mss, 0, 0, (*state)->tag, NULL, NULL); + (*state)->src.mss, 0, 0, (*state)->tag, NULL, NULL, route_to_ro0); REASON_SET(reason, PFRES_SYNPROXY); return (PF_SYNPROXY_DROP); } else if (((th->th_flags & (TH_SYN|TH_ACK)) != @@ -4667,7 +4701,7 @@ pd->src, th->th_dport, th->th_sport, ntohl(th->th_ack), ntohl(th->th_seq) + 1, TH_ACK, (*state)->src.max_win, 0, 0, 0, - (*state)->tag, NULL, NULL); + (*state)->tag, NULL, NULL, NULL); #ifdef __FreeBSD__ pf_send_tcp(NULL, (*state)->rule.ptr, pd->af, #else @@ -4677,7 +4711,7 @@ sk->port[pd->sidx], sk->port[pd->didx], (*state)->src.seqhi + 1, (*state)->src.seqlo + 1, TH_ACK, (*state)->dst.max_win, 0, 0, 1, - 0, NULL, NULL); + 0, NULL, NULL, route_to_ro0); (*state)->src.seqdiff = (*state)->dst.seqhi - (*state)->src.seqlo; (*state)->dst.seqdiff = (*state)->src.seqhi -