1e0bfbfceSBjoern A. Zeeb /* $OpenBSD: filter.c,v 1.8 2008/06/13 07:25:26 claudio Exp $ */ 267ecd4f3SMax Laier 367ecd4f3SMax Laier /* 467ecd4f3SMax Laier * Copyright (c) 2004, 2005 Camiel Dobbelaar, <cd@sentia.nl> 567ecd4f3SMax Laier * 667ecd4f3SMax Laier * Permission to use, copy, modify, and distribute this software for any 767ecd4f3SMax Laier * purpose with or without fee is hereby granted, provided that the above 867ecd4f3SMax Laier * copyright notice and this permission notice appear in all copies. 967ecd4f3SMax Laier * 1067ecd4f3SMax Laier * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1167ecd4f3SMax Laier * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1267ecd4f3SMax Laier * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1367ecd4f3SMax Laier * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1467ecd4f3SMax Laier * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1567ecd4f3SMax Laier * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1667ecd4f3SMax Laier * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1767ecd4f3SMax Laier */ 1867ecd4f3SMax Laier 1967ecd4f3SMax Laier #include <sys/ioctl.h> 2067ecd4f3SMax Laier #include <sys/types.h> 2167ecd4f3SMax Laier #include <sys/socket.h> 2267ecd4f3SMax Laier 2367ecd4f3SMax Laier #include <net/if.h> 2467ecd4f3SMax Laier #include <net/pfvar.h> 2567ecd4f3SMax Laier #include <netinet/in.h> 2667ecd4f3SMax Laier #include <netinet/tcp.h> 2767ecd4f3SMax Laier #include <arpa/inet.h> 2867ecd4f3SMax Laier 2967ecd4f3SMax Laier #include <err.h> 3067ecd4f3SMax Laier #include <errno.h> 3195be9288SKristof Provost #include <libpfctl.h> 3267ecd4f3SMax Laier #include <fcntl.h> 3367ecd4f3SMax Laier #include <stdio.h> 3467ecd4f3SMax Laier #include <string.h> 3567ecd4f3SMax Laier #include <unistd.h> 3667ecd4f3SMax Laier 3767ecd4f3SMax Laier #include "filter.h" 3867ecd4f3SMax Laier 3967ecd4f3SMax Laier /* From netinet/in.h, but only _KERNEL_ gets them. */ 4067ecd4f3SMax Laier #define satosin(sa) ((struct sockaddr_in *)(sa)) 4167ecd4f3SMax Laier #define satosin6(sa) ((struct sockaddr_in6 *)(sa)) 4267ecd4f3SMax Laier 4367ecd4f3SMax Laier enum { TRANS_FILTER = 0, TRANS_NAT, TRANS_RDR, TRANS_SIZE }; 4467ecd4f3SMax Laier 4567ecd4f3SMax Laier int prepare_rule(u_int32_t, int, struct sockaddr *, struct sockaddr *, 4667ecd4f3SMax Laier u_int16_t); 4767ecd4f3SMax Laier int server_lookup4(struct sockaddr_in *, struct sockaddr_in *, 4867ecd4f3SMax Laier struct sockaddr_in *); 4967ecd4f3SMax Laier int server_lookup6(struct sockaddr_in6 *, struct sockaddr_in6 *, 5067ecd4f3SMax Laier struct sockaddr_in6 *); 5167ecd4f3SMax Laier 5267ecd4f3SMax Laier static struct pfioc_pooladdr pfp; 53e9eb0941SKristof Provost static struct pfctl_rule pfrule; 54e9eb0941SKristof Provost static char pfanchor[PF_ANCHOR_NAME_SIZE]; 55e9eb0941SKristof Provost static char pfanchor_call[PF_ANCHOR_NAME_SIZE]; 56e9eb0941SKristof Provost static uint32_t pfticket; 57e9eb0941SKristof Provost static uint32_t pfpool_ticket; 5867ecd4f3SMax Laier static struct pfioc_trans pft; 5967ecd4f3SMax Laier static struct pfioc_trans_e pfte[TRANS_SIZE]; 60044243fcSKristof Provost static int rule_log; 61324fd7ecSKristof Provost static struct pfctl_handle *pfh = NULL; 62e0bfbfceSBjoern A. Zeeb static const char *qname, *tagname; 6367ecd4f3SMax Laier 6467ecd4f3SMax Laier int 6567ecd4f3SMax Laier add_filter(u_int32_t id, u_int8_t dir, struct sockaddr *src, 6667ecd4f3SMax Laier struct sockaddr *dst, u_int16_t d_port) 6767ecd4f3SMax Laier { 6867ecd4f3SMax Laier if (!src || !dst || !d_port) { 6967ecd4f3SMax Laier errno = EINVAL; 7067ecd4f3SMax Laier return (-1); 7167ecd4f3SMax Laier } 7267ecd4f3SMax Laier 7367ecd4f3SMax Laier if (prepare_rule(id, PF_RULESET_FILTER, src, dst, d_port) == -1) 7467ecd4f3SMax Laier return (-1); 7567ecd4f3SMax Laier 76e9eb0941SKristof Provost pfrule.direction = dir; 77324fd7ecSKristof Provost if (pfctl_add_rule_h(pfh, &pfrule, pfanchor, pfanchor_call, 78e9eb0941SKristof Provost pfticket, pfpool_ticket)) 7967ecd4f3SMax Laier return (-1); 8067ecd4f3SMax Laier 8167ecd4f3SMax Laier return (0); 8267ecd4f3SMax Laier } 8367ecd4f3SMax Laier 8467ecd4f3SMax Laier int 8567ecd4f3SMax Laier add_nat(u_int32_t id, struct sockaddr *src, struct sockaddr *dst, 8667ecd4f3SMax Laier u_int16_t d_port, struct sockaddr *nat, u_int16_t nat_range_low, 8767ecd4f3SMax Laier u_int16_t nat_range_high) 8867ecd4f3SMax Laier { 8967ecd4f3SMax Laier if (!src || !dst || !d_port || !nat || !nat_range_low || 9067ecd4f3SMax Laier (src->sa_family != nat->sa_family)) { 9167ecd4f3SMax Laier errno = EINVAL; 9267ecd4f3SMax Laier return (-1); 9367ecd4f3SMax Laier } 9467ecd4f3SMax Laier 9567ecd4f3SMax Laier if (prepare_rule(id, PF_RULESET_NAT, src, dst, d_port) == -1) 9667ecd4f3SMax Laier return (-1); 9767ecd4f3SMax Laier 9867ecd4f3SMax Laier if (nat->sa_family == AF_INET) { 9967ecd4f3SMax Laier memcpy(&pfp.addr.addr.v.a.addr.v4, 10067ecd4f3SMax Laier &satosin(nat)->sin_addr.s_addr, 4); 10167ecd4f3SMax Laier memset(&pfp.addr.addr.v.a.mask.addr8, 255, 4); 10267ecd4f3SMax Laier } else { 10367ecd4f3SMax Laier memcpy(&pfp.addr.addr.v.a.addr.v6, 10467ecd4f3SMax Laier &satosin6(nat)->sin6_addr.s6_addr, 16); 10567ecd4f3SMax Laier memset(&pfp.addr.addr.v.a.mask.addr8, 255, 16); 10667ecd4f3SMax Laier } 107044243fcSKristof Provost if (ioctl(pfctl_fd(pfh), DIOCADDADDR, &pfp) == -1) 10867ecd4f3SMax Laier return (-1); 10967ecd4f3SMax Laier 110*096efeb6SKristof Provost pfrule.rdr.proxy_port[0] = nat_range_low; 111*096efeb6SKristof Provost pfrule.rdr.proxy_port[1] = nat_range_high; 112324fd7ecSKristof Provost if (pfctl_add_rule_h(pfh, &pfrule, pfanchor, pfanchor_call, 113e9eb0941SKristof Provost pfticket, pfpool_ticket)) 11467ecd4f3SMax Laier return (-1); 11567ecd4f3SMax Laier 11667ecd4f3SMax Laier return (0); 11767ecd4f3SMax Laier } 11867ecd4f3SMax Laier 11967ecd4f3SMax Laier int 12067ecd4f3SMax Laier add_rdr(u_int32_t id, struct sockaddr *src, struct sockaddr *dst, 12167ecd4f3SMax Laier u_int16_t d_port, struct sockaddr *rdr, u_int16_t rdr_port) 12267ecd4f3SMax Laier { 12367ecd4f3SMax Laier if (!src || !dst || !d_port || !rdr || !rdr_port || 12467ecd4f3SMax Laier (src->sa_family != rdr->sa_family)) { 12567ecd4f3SMax Laier errno = EINVAL; 12667ecd4f3SMax Laier return (-1); 12767ecd4f3SMax Laier } 12867ecd4f3SMax Laier 12967ecd4f3SMax Laier if (prepare_rule(id, PF_RULESET_RDR, src, dst, d_port) == -1) 13067ecd4f3SMax Laier return (-1); 13167ecd4f3SMax Laier 13267ecd4f3SMax Laier if (rdr->sa_family == AF_INET) { 13367ecd4f3SMax Laier memcpy(&pfp.addr.addr.v.a.addr.v4, 13467ecd4f3SMax Laier &satosin(rdr)->sin_addr.s_addr, 4); 13567ecd4f3SMax Laier memset(&pfp.addr.addr.v.a.mask.addr8, 255, 4); 13667ecd4f3SMax Laier } else { 13767ecd4f3SMax Laier memcpy(&pfp.addr.addr.v.a.addr.v6, 13867ecd4f3SMax Laier &satosin6(rdr)->sin6_addr.s6_addr, 16); 13967ecd4f3SMax Laier memset(&pfp.addr.addr.v.a.mask.addr8, 255, 16); 14067ecd4f3SMax Laier } 141044243fcSKristof Provost if (ioctl(pfctl_fd(pfh), DIOCADDADDR, &pfp) == -1) 14267ecd4f3SMax Laier return (-1); 14367ecd4f3SMax Laier 144*096efeb6SKristof Provost pfrule.rdr.proxy_port[0] = rdr_port; 145324fd7ecSKristof Provost if (pfctl_add_rule_h(pfh, &pfrule, pfanchor, pfanchor_call, 146e9eb0941SKristof Provost pfticket, pfpool_ticket)) 14767ecd4f3SMax Laier return (-1); 14867ecd4f3SMax Laier 14967ecd4f3SMax Laier return (0); 15067ecd4f3SMax Laier } 15167ecd4f3SMax Laier 15267ecd4f3SMax Laier int 15367ecd4f3SMax Laier do_commit(void) 15467ecd4f3SMax Laier { 155044243fcSKristof Provost if (ioctl(pfctl_fd(pfh), DIOCXCOMMIT, &pft) == -1) 15667ecd4f3SMax Laier return (-1); 15767ecd4f3SMax Laier 15867ecd4f3SMax Laier return (0); 15967ecd4f3SMax Laier } 16067ecd4f3SMax Laier 16167ecd4f3SMax Laier int 16267ecd4f3SMax Laier do_rollback(void) 16367ecd4f3SMax Laier { 164044243fcSKristof Provost if (ioctl(pfctl_fd(pfh), DIOCXROLLBACK, &pft) == -1) 16567ecd4f3SMax Laier return (-1); 16667ecd4f3SMax Laier 16767ecd4f3SMax Laier return (0); 16867ecd4f3SMax Laier } 16967ecd4f3SMax Laier 17067ecd4f3SMax Laier void 171e0bfbfceSBjoern A. Zeeb init_filter(const char *opt_qname, const char *opt_tagname, int opt_verbose) 17267ecd4f3SMax Laier { 173ddd08375SKristof Provost struct pfctl_status *status; 17467ecd4f3SMax Laier 17567ecd4f3SMax Laier qname = opt_qname; 176e0bfbfceSBjoern A. Zeeb tagname = opt_tagname; 17767ecd4f3SMax Laier 17867ecd4f3SMax Laier if (opt_verbose == 1) 17967ecd4f3SMax Laier rule_log = PF_LOG; 18067ecd4f3SMax Laier else if (opt_verbose == 2) 18167ecd4f3SMax Laier rule_log = PF_LOG_ALL; 18267ecd4f3SMax Laier 183324fd7ecSKristof Provost pfh = pfctl_open(PF_DEVICE); 184324fd7ecSKristof Provost if (pfh == NULL) 185324fd7ecSKristof Provost err(1, "pfctl_open"); 1865824df8dSKristof Provost status = pfctl_get_status_h(pfh); 187ddd08375SKristof Provost if (status == NULL) 18867ecd4f3SMax Laier err(1, "DIOCGETSTATUS"); 189ddd08375SKristof Provost if (!status->running) 19067ecd4f3SMax Laier errx(1, "pf is disabled"); 191ddd08375SKristof Provost 192ddd08375SKristof Provost pfctl_free_status(status); 19367ecd4f3SMax Laier } 19467ecd4f3SMax Laier 19567ecd4f3SMax Laier int 19667ecd4f3SMax Laier prepare_commit(u_int32_t id) 19767ecd4f3SMax Laier { 19867ecd4f3SMax Laier char an[PF_ANCHOR_NAME_SIZE]; 19967ecd4f3SMax Laier int i; 20067ecd4f3SMax Laier 20167ecd4f3SMax Laier memset(&pft, 0, sizeof pft); 20267ecd4f3SMax Laier pft.size = TRANS_SIZE; 20367ecd4f3SMax Laier pft.esize = sizeof pfte[0]; 20467ecd4f3SMax Laier pft.array = pfte; 20567ecd4f3SMax Laier 20667ecd4f3SMax Laier snprintf(an, PF_ANCHOR_NAME_SIZE, "%s/%d.%d", FTP_PROXY_ANCHOR, 20767ecd4f3SMax Laier getpid(), id); 20867ecd4f3SMax Laier for (i = 0; i < TRANS_SIZE; i++) { 20967ecd4f3SMax Laier memset(&pfte[i], 0, sizeof pfte[0]); 21067ecd4f3SMax Laier strlcpy(pfte[i].anchor, an, PF_ANCHOR_NAME_SIZE); 21167ecd4f3SMax Laier switch (i) { 21267ecd4f3SMax Laier case TRANS_FILTER: 21367ecd4f3SMax Laier pfte[i].rs_num = PF_RULESET_FILTER; 21467ecd4f3SMax Laier break; 21567ecd4f3SMax Laier case TRANS_NAT: 21667ecd4f3SMax Laier pfte[i].rs_num = PF_RULESET_NAT; 21767ecd4f3SMax Laier break; 21867ecd4f3SMax Laier case TRANS_RDR: 21967ecd4f3SMax Laier pfte[i].rs_num = PF_RULESET_RDR; 22067ecd4f3SMax Laier break; 22167ecd4f3SMax Laier default: 22267ecd4f3SMax Laier errno = EINVAL; 22367ecd4f3SMax Laier return (-1); 22467ecd4f3SMax Laier } 22567ecd4f3SMax Laier } 22667ecd4f3SMax Laier 227044243fcSKristof Provost if (ioctl(pfctl_fd(pfh), DIOCXBEGIN, &pft) == -1) 22867ecd4f3SMax Laier return (-1); 22967ecd4f3SMax Laier 23067ecd4f3SMax Laier return (0); 23167ecd4f3SMax Laier } 23267ecd4f3SMax Laier 23367ecd4f3SMax Laier int 23467ecd4f3SMax Laier prepare_rule(u_int32_t id, int rs_num, struct sockaddr *src, 23567ecd4f3SMax Laier struct sockaddr *dst, u_int16_t d_port) 23667ecd4f3SMax Laier { 23767ecd4f3SMax Laier char an[PF_ANCHOR_NAME_SIZE]; 23867ecd4f3SMax Laier 23967ecd4f3SMax Laier if ((src->sa_family != AF_INET && src->sa_family != AF_INET6) || 24067ecd4f3SMax Laier (src->sa_family != dst->sa_family)) { 24167ecd4f3SMax Laier errno = EPROTONOSUPPORT; 24267ecd4f3SMax Laier return (-1); 24367ecd4f3SMax Laier } 24467ecd4f3SMax Laier 24567ecd4f3SMax Laier memset(&pfp, 0, sizeof pfp); 246e9eb0941SKristof Provost memset(&pfrule, 0, sizeof pfrule); 24767ecd4f3SMax Laier snprintf(an, PF_ANCHOR_NAME_SIZE, "%s/%d.%d", FTP_PROXY_ANCHOR, 24867ecd4f3SMax Laier getpid(), id); 24967ecd4f3SMax Laier strlcpy(pfp.anchor, an, PF_ANCHOR_NAME_SIZE); 250e9eb0941SKristof Provost strlcpy(pfanchor, an, PF_ANCHOR_NAME_SIZE); 25167ecd4f3SMax Laier 25267ecd4f3SMax Laier switch (rs_num) { 25367ecd4f3SMax Laier case PF_RULESET_FILTER: 254e9eb0941SKristof Provost pfticket = pfte[TRANS_FILTER].ticket; 25567ecd4f3SMax Laier break; 25667ecd4f3SMax Laier case PF_RULESET_NAT: 257e9eb0941SKristof Provost pfticket = pfte[TRANS_NAT].ticket; 25867ecd4f3SMax Laier break; 25967ecd4f3SMax Laier case PF_RULESET_RDR: 260e9eb0941SKristof Provost pfticket = pfte[TRANS_RDR].ticket; 26167ecd4f3SMax Laier break; 26267ecd4f3SMax Laier default: 26367ecd4f3SMax Laier errno = EINVAL; 26467ecd4f3SMax Laier return (-1); 26567ecd4f3SMax Laier } 266ba2a9207SKristof Provost if (pfctl_begin_addrs(pfh, &pfp.ticket)) 26767ecd4f3SMax Laier return (-1); 268e9eb0941SKristof Provost pfpool_ticket = pfp.ticket; 26967ecd4f3SMax Laier 27067ecd4f3SMax Laier /* Generic for all rule types. */ 271e9eb0941SKristof Provost pfrule.af = src->sa_family; 272e9eb0941SKristof Provost pfrule.proto = IPPROTO_TCP; 273e9eb0941SKristof Provost pfrule.src.addr.type = PF_ADDR_ADDRMASK; 274e9eb0941SKristof Provost pfrule.dst.addr.type = PF_ADDR_ADDRMASK; 27567ecd4f3SMax Laier if (src->sa_family == AF_INET) { 276e9eb0941SKristof Provost memcpy(&pfrule.src.addr.v.a.addr.v4, 27767ecd4f3SMax Laier &satosin(src)->sin_addr.s_addr, 4); 278e9eb0941SKristof Provost memset(&pfrule.src.addr.v.a.mask.addr8, 255, 4); 279e9eb0941SKristof Provost memcpy(&pfrule.dst.addr.v.a.addr.v4, 28067ecd4f3SMax Laier &satosin(dst)->sin_addr.s_addr, 4); 281e9eb0941SKristof Provost memset(&pfrule.dst.addr.v.a.mask.addr8, 255, 4); 28267ecd4f3SMax Laier } else { 283e9eb0941SKristof Provost memcpy(&pfrule.src.addr.v.a.addr.v6, 28467ecd4f3SMax Laier &satosin6(src)->sin6_addr.s6_addr, 16); 285e9eb0941SKristof Provost memset(&pfrule.src.addr.v.a.mask.addr8, 255, 16); 286e9eb0941SKristof Provost memcpy(&pfrule.dst.addr.v.a.addr.v6, 28767ecd4f3SMax Laier &satosin6(dst)->sin6_addr.s6_addr, 16); 288e9eb0941SKristof Provost memset(&pfrule.dst.addr.v.a.mask.addr8, 255, 16); 28967ecd4f3SMax Laier } 290e9eb0941SKristof Provost pfrule.dst.port_op = PF_OP_EQ; 291e9eb0941SKristof Provost pfrule.dst.port[0] = htons(d_port); 29267ecd4f3SMax Laier 29367ecd4f3SMax Laier switch (rs_num) { 29467ecd4f3SMax Laier case PF_RULESET_FILTER: 29567ecd4f3SMax Laier /* 296e0bfbfceSBjoern A. Zeeb * pass [quick] [log] inet[6] proto tcp \ 29767ecd4f3SMax Laier * from $src to $dst port = $d_port flags S/SA keep state 298e0bfbfceSBjoern A. Zeeb * (max 1) [queue qname] [tag tagname] 29967ecd4f3SMax Laier */ 300e9eb0941SKristof Provost pfrule.action = PF_PASS; 301e9eb0941SKristof Provost pfrule.quick = 1; 302e9eb0941SKristof Provost pfrule.log = rule_log; 303e9eb0941SKristof Provost pfrule.keep_state = 1; 304e9eb0941SKristof Provost pfrule.flags = TH_SYN; 305e9eb0941SKristof Provost pfrule.flagset = (TH_SYN|TH_ACK); 306e9eb0941SKristof Provost pfrule.max_states = 1; 30767ecd4f3SMax Laier if (qname != NULL) 308e9eb0941SKristof Provost strlcpy(pfrule.qname, qname, sizeof pfrule.qname); 309e0bfbfceSBjoern A. Zeeb if (tagname != NULL) { 310e9eb0941SKristof Provost pfrule.quick = 0; 311e9eb0941SKristof Provost strlcpy(pfrule.tagname, tagname, 312e9eb0941SKristof Provost sizeof pfrule.tagname); 313e0bfbfceSBjoern A. Zeeb } 31467ecd4f3SMax Laier break; 31567ecd4f3SMax Laier case PF_RULESET_NAT: 31667ecd4f3SMax Laier /* 31767ecd4f3SMax Laier * nat inet[6] proto tcp from $src to $dst port $d_port -> $nat 31867ecd4f3SMax Laier */ 319e9eb0941SKristof Provost pfrule.action = PF_NAT; 32067ecd4f3SMax Laier break; 32167ecd4f3SMax Laier case PF_RULESET_RDR: 32267ecd4f3SMax Laier /* 32367ecd4f3SMax Laier * rdr inet[6] proto tcp from $src to $dst port $d_port -> $rdr 32467ecd4f3SMax Laier */ 325e9eb0941SKristof Provost pfrule.action = PF_RDR; 32667ecd4f3SMax Laier break; 32767ecd4f3SMax Laier default: 32867ecd4f3SMax Laier errno = EINVAL; 32967ecd4f3SMax Laier return (-1); 33067ecd4f3SMax Laier } 33167ecd4f3SMax Laier 33267ecd4f3SMax Laier return (0); 33367ecd4f3SMax Laier } 33467ecd4f3SMax Laier 33567ecd4f3SMax Laier int 33667ecd4f3SMax Laier server_lookup(struct sockaddr *client, struct sockaddr *proxy, 33767ecd4f3SMax Laier struct sockaddr *server) 33867ecd4f3SMax Laier { 33967ecd4f3SMax Laier if (client->sa_family == AF_INET) 34067ecd4f3SMax Laier return (server_lookup4(satosin(client), satosin(proxy), 34167ecd4f3SMax Laier satosin(server))); 34267ecd4f3SMax Laier 34367ecd4f3SMax Laier if (client->sa_family == AF_INET6) 34467ecd4f3SMax Laier return (server_lookup6(satosin6(client), satosin6(proxy), 34567ecd4f3SMax Laier satosin6(server))); 34667ecd4f3SMax Laier 34767ecd4f3SMax Laier errno = EPROTONOSUPPORT; 34867ecd4f3SMax Laier return (-1); 34967ecd4f3SMax Laier } 35067ecd4f3SMax Laier 35167ecd4f3SMax Laier int 35267ecd4f3SMax Laier server_lookup4(struct sockaddr_in *client, struct sockaddr_in *proxy, 35367ecd4f3SMax Laier struct sockaddr_in *server) 35467ecd4f3SMax Laier { 35571d3c704SKristof Provost struct pfctl_natlook_key k = {}; 35671d3c704SKristof Provost struct pfctl_natlook r = {}; 35767ecd4f3SMax Laier 35871d3c704SKristof Provost k.direction = PF_OUT; 35971d3c704SKristof Provost k.af = AF_INET; 36071d3c704SKristof Provost k.proto = IPPROTO_TCP; 36171d3c704SKristof Provost memcpy(&k.saddr.v4, &client->sin_addr.s_addr, sizeof(k.saddr.v4)); 36271d3c704SKristof Provost memcpy(&k.daddr.v4, &proxy->sin_addr.s_addr, sizeof(k.daddr.v4)); 36371d3c704SKristof Provost k.sport = client->sin_port; 36471d3c704SKristof Provost k.dport = proxy->sin_port; 36567ecd4f3SMax Laier 36671d3c704SKristof Provost if (pfctl_natlook(pfh, &k, &r)) 36767ecd4f3SMax Laier return (-1); 36867ecd4f3SMax Laier 36967ecd4f3SMax Laier memset(server, 0, sizeof(struct sockaddr_in)); 37067ecd4f3SMax Laier server->sin_len = sizeof(struct sockaddr_in); 37167ecd4f3SMax Laier server->sin_family = AF_INET; 37271d3c704SKristof Provost memcpy(&server->sin_addr.s_addr, &r.daddr.v4, 37371d3c704SKristof Provost sizeof(server->sin_addr.s_addr)); 37471d3c704SKristof Provost server->sin_port = r.dport; 37567ecd4f3SMax Laier 37667ecd4f3SMax Laier return (0); 37767ecd4f3SMax Laier } 37867ecd4f3SMax Laier 37967ecd4f3SMax Laier int 38067ecd4f3SMax Laier server_lookup6(struct sockaddr_in6 *client, struct sockaddr_in6 *proxy, 38167ecd4f3SMax Laier struct sockaddr_in6 *server) 38267ecd4f3SMax Laier { 38371d3c704SKristof Provost struct pfctl_natlook_key k = {}; 38471d3c704SKristof Provost struct pfctl_natlook r = {}; 38567ecd4f3SMax Laier 38671d3c704SKristof Provost k.direction = PF_OUT; 38771d3c704SKristof Provost k.af = AF_INET6; 38871d3c704SKristof Provost k.proto = IPPROTO_TCP; 38971d3c704SKristof Provost memcpy(&k.saddr.v6, &client->sin6_addr.s6_addr, sizeof(k.saddr.v6)); 39071d3c704SKristof Provost memcpy(&k.daddr.v6, &proxy->sin6_addr.s6_addr, sizeof(k.daddr.v6)); 39171d3c704SKristof Provost k.sport = client->sin6_port; 39271d3c704SKristof Provost k.dport = proxy->sin6_port; 39367ecd4f3SMax Laier 39471d3c704SKristof Provost if (pfctl_natlook(pfh, &k, &r)) 39567ecd4f3SMax Laier return (-1); 39667ecd4f3SMax Laier 39767ecd4f3SMax Laier memset(server, 0, sizeof(struct sockaddr_in6)); 39867ecd4f3SMax Laier server->sin6_len = sizeof(struct sockaddr_in6); 39967ecd4f3SMax Laier server->sin6_family = AF_INET6; 40071d3c704SKristof Provost memcpy(&server->sin6_addr.s6_addr, &r.daddr.v6, 40171d3c704SKristof Provost sizeof(server->sin6_addr)); 40271d3c704SKristof Provost server->sin6_port = r.dport; 40367ecd4f3SMax Laier 40467ecd4f3SMax Laier return (0); 40567ecd4f3SMax Laier } 406