167ecd4f3SMax Laier /* $OpenBSD: filter.c,v 1.1 2005/12/28 19:07:07 jcs Exp $ */ 25ee7cd21SMax Laier /* $FreeBSD$ */ 367ecd4f3SMax Laier 467ecd4f3SMax Laier /* 567ecd4f3SMax Laier * Copyright (c) 2004, 2005 Camiel Dobbelaar, <cd@sentia.nl> 667ecd4f3SMax Laier * 767ecd4f3SMax Laier * Permission to use, copy, modify, and distribute this software for any 867ecd4f3SMax Laier * purpose with or without fee is hereby granted, provided that the above 967ecd4f3SMax Laier * copyright notice and this permission notice appear in all copies. 1067ecd4f3SMax Laier * 1167ecd4f3SMax Laier * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1267ecd4f3SMax Laier * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1367ecd4f3SMax Laier * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1467ecd4f3SMax Laier * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1567ecd4f3SMax Laier * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1667ecd4f3SMax Laier * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1767ecd4f3SMax Laier * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1867ecd4f3SMax Laier */ 1967ecd4f3SMax Laier 2067ecd4f3SMax Laier #include <syslog.h> 2167ecd4f3SMax Laier 2267ecd4f3SMax Laier #include <sys/ioctl.h> 2367ecd4f3SMax Laier #include <sys/types.h> 2467ecd4f3SMax Laier #include <sys/socket.h> 2567ecd4f3SMax Laier 2667ecd4f3SMax Laier #include <net/if.h> 2767ecd4f3SMax Laier #include <net/pfvar.h> 2867ecd4f3SMax Laier #include <netinet/in.h> 2967ecd4f3SMax Laier #include <netinet/tcp.h> 3067ecd4f3SMax Laier #include <arpa/inet.h> 3167ecd4f3SMax Laier 3267ecd4f3SMax Laier #include <err.h> 3367ecd4f3SMax Laier #include <errno.h> 3467ecd4f3SMax Laier #include <fcntl.h> 3595be9288SKristof Provost #include <libpfctl.h> 3667ecd4f3SMax Laier #include <stdio.h> 3767ecd4f3SMax Laier #include <stdlib.h> 3867ecd4f3SMax Laier #include <string.h> 3967ecd4f3SMax Laier #include <unistd.h> 4067ecd4f3SMax Laier 4167ecd4f3SMax Laier #include "filter.h" 4267ecd4f3SMax Laier 4367ecd4f3SMax Laier /* From netinet/in.h, but only _KERNEL_ gets them. */ 4467ecd4f3SMax Laier #define satosin(sa) ((struct sockaddr_in *)(sa)) 4567ecd4f3SMax Laier #define satosin6(sa) ((struct sockaddr_in6 *)(sa)) 4667ecd4f3SMax Laier 4767ecd4f3SMax Laier enum { TRANS_FILTER = 0, TRANS_NAT, TRANS_RDR, TRANS_SIZE }; 4867ecd4f3SMax Laier 4967ecd4f3SMax Laier int prepare_rule(u_int32_t, int, struct sockaddr *, struct sockaddr *, 5067ecd4f3SMax Laier u_int16_t, u_int8_t); 5167ecd4f3SMax Laier int server_lookup4(struct sockaddr_in *, struct sockaddr_in *, 5267ecd4f3SMax Laier struct sockaddr_in *, u_int8_t); 5367ecd4f3SMax Laier int server_lookup6(struct sockaddr_in6 *, struct sockaddr_in6 *, 5467ecd4f3SMax Laier struct sockaddr_in6 *, u_int8_t); 5567ecd4f3SMax Laier 5667ecd4f3SMax Laier static struct pfioc_pooladdr pfp; 57e9eb0941SKristof Provost static struct pfctl_rule pfrule; 58e9eb0941SKristof Provost static uint32_t pfticket; 59e9eb0941SKristof Provost static uint32_t pfpool_ticket; 60e9eb0941SKristof Provost static char pfanchor[PF_ANCHOR_NAME_SIZE]; 61e9eb0941SKristof Provost static char pfanchor_call[PF_ANCHOR_NAME_SIZE]; 6267ecd4f3SMax Laier static struct pfioc_trans pft; 6367ecd4f3SMax Laier static struct pfioc_trans_e pfte[TRANS_SIZE]; 64044243fcSKristof Provost static int rule_log; 65324fd7ecSKristof Provost static struct pfctl_handle *pfh = NULL; 6667ecd4f3SMax Laier static char *qname; 6767ecd4f3SMax Laier 6867ecd4f3SMax Laier int 6967ecd4f3SMax Laier add_filter(u_int32_t id, u_int8_t dir, struct sockaddr *src, 7067ecd4f3SMax Laier struct sockaddr *dst, u_int16_t d_port, u_int8_t proto) 7167ecd4f3SMax Laier { 7267ecd4f3SMax Laier if (!src || !dst || !d_port || !proto) { 7367ecd4f3SMax Laier errno = EINVAL; 7467ecd4f3SMax Laier return (-1); 7567ecd4f3SMax Laier } 7667ecd4f3SMax Laier 7767ecd4f3SMax Laier if (prepare_rule(id, PF_RULESET_FILTER, src, dst, d_port, proto) == -1) 7867ecd4f3SMax Laier return (-1); 7967ecd4f3SMax Laier 80e9eb0941SKristof Provost pfrule.direction = dir; 81324fd7ecSKristof Provost if (pfctl_add_rule_h(pfh, &pfrule, pfanchor, pfanchor_call, 82e9eb0941SKristof Provost pfticket, pfpool_ticket)) 8367ecd4f3SMax Laier return (-1); 8467ecd4f3SMax Laier 8567ecd4f3SMax Laier return (0); 8667ecd4f3SMax Laier } 8767ecd4f3SMax Laier 8867ecd4f3SMax Laier int 8967ecd4f3SMax Laier add_nat(u_int32_t id, struct sockaddr *src, struct sockaddr *dst, 9067ecd4f3SMax Laier u_int16_t d_port, struct sockaddr *nat, u_int16_t nat_range_low, 9167ecd4f3SMax Laier u_int16_t nat_range_high, u_int8_t proto) 9267ecd4f3SMax Laier { 9367ecd4f3SMax Laier if (!src || !dst || !d_port || !nat || !nat_range_low || !proto || 9467ecd4f3SMax Laier (src->sa_family != nat->sa_family)) { 9567ecd4f3SMax Laier errno = EINVAL; 9667ecd4f3SMax Laier return (-1); 9767ecd4f3SMax Laier } 9867ecd4f3SMax Laier 9967ecd4f3SMax Laier if (prepare_rule(id, PF_RULESET_NAT, src, dst, d_port, proto) == -1) 10067ecd4f3SMax Laier return (-1); 10167ecd4f3SMax Laier 10267ecd4f3SMax Laier if (nat->sa_family == AF_INET) { 10367ecd4f3SMax Laier memcpy(&pfp.addr.addr.v.a.addr.v4, 10467ecd4f3SMax Laier &satosin(nat)->sin_addr.s_addr, 4); 10567ecd4f3SMax Laier memset(&pfp.addr.addr.v.a.mask.addr8, 255, 4); 10667ecd4f3SMax Laier } else { 10767ecd4f3SMax Laier memcpy(&pfp.addr.addr.v.a.addr.v6, 10867ecd4f3SMax Laier &satosin6(nat)->sin6_addr.s6_addr, 16); 10967ecd4f3SMax Laier memset(&pfp.addr.addr.v.a.mask.addr8, 255, 16); 11067ecd4f3SMax Laier } 111044243fcSKristof Provost if (ioctl(pfctl_fd(pfh), DIOCADDADDR, &pfp) == -1) 11267ecd4f3SMax Laier return (-1); 11367ecd4f3SMax Laier 114*096efeb6SKristof Provost pfrule.rdr.proxy_port[0] = nat_range_low; 115*096efeb6SKristof Provost pfrule.rdr.proxy_port[1] = nat_range_high; 116324fd7ecSKristof Provost if (pfctl_add_rule_h(pfh, &pfrule, pfanchor, pfanchor_call, 117e9eb0941SKristof Provost pfticket, pfpool_ticket)) 11867ecd4f3SMax Laier return (-1); 11967ecd4f3SMax Laier 12067ecd4f3SMax Laier return (0); 12167ecd4f3SMax Laier } 12267ecd4f3SMax Laier 12367ecd4f3SMax Laier int 12467ecd4f3SMax Laier add_rdr(u_int32_t id, struct sockaddr *src, struct sockaddr *dst, 12567ecd4f3SMax Laier u_int16_t d_port, struct sockaddr *rdr, u_int16_t rdr_port, u_int8_t proto) 12667ecd4f3SMax Laier { 12767ecd4f3SMax Laier if (!src || !dst || !d_port || !rdr || !rdr_port || !proto || 12867ecd4f3SMax Laier (src->sa_family != rdr->sa_family)) { 12967ecd4f3SMax Laier errno = EINVAL; 13067ecd4f3SMax Laier return (-1); 13167ecd4f3SMax Laier } 13267ecd4f3SMax Laier 13367ecd4f3SMax Laier if (prepare_rule(id, PF_RULESET_RDR, src, dst, d_port, proto) == -1) 13467ecd4f3SMax Laier return (-1); 13567ecd4f3SMax Laier 13667ecd4f3SMax Laier if (rdr->sa_family == AF_INET) { 13767ecd4f3SMax Laier memcpy(&pfp.addr.addr.v.a.addr.v4, 13867ecd4f3SMax Laier &satosin(rdr)->sin_addr.s_addr, 4); 13967ecd4f3SMax Laier memset(&pfp.addr.addr.v.a.mask.addr8, 255, 4); 14067ecd4f3SMax Laier } else { 14167ecd4f3SMax Laier memcpy(&pfp.addr.addr.v.a.addr.v6, 14267ecd4f3SMax Laier &satosin6(rdr)->sin6_addr.s6_addr, 16); 14367ecd4f3SMax Laier memset(&pfp.addr.addr.v.a.mask.addr8, 255, 16); 14467ecd4f3SMax Laier } 145044243fcSKristof Provost if (ioctl(pfctl_fd(pfh), DIOCADDADDR, &pfp) == -1) 14667ecd4f3SMax Laier return (-1); 14767ecd4f3SMax Laier 148*096efeb6SKristof Provost pfrule.rdr.proxy_port[0] = rdr_port; 149324fd7ecSKristof Provost if (pfctl_add_rule_h(pfh, &pfrule, pfanchor, pfanchor_call, 150e9eb0941SKristof Provost pfticket, pfpool_ticket)) 15167ecd4f3SMax Laier return (-1); 15267ecd4f3SMax Laier 15367ecd4f3SMax Laier return (0); 15467ecd4f3SMax Laier } 15567ecd4f3SMax Laier 15667ecd4f3SMax Laier int 15767ecd4f3SMax Laier do_commit(void) 15867ecd4f3SMax Laier { 159044243fcSKristof Provost if (ioctl(pfctl_fd(pfh), DIOCXCOMMIT, &pft) == -1) 16067ecd4f3SMax Laier return (-1); 16167ecd4f3SMax Laier 16267ecd4f3SMax Laier return (0); 16367ecd4f3SMax Laier } 16467ecd4f3SMax Laier 16567ecd4f3SMax Laier int 16667ecd4f3SMax Laier do_rollback(void) 16767ecd4f3SMax Laier { 168044243fcSKristof Provost if (ioctl(pfctl_fd(pfh), DIOCXROLLBACK, &pft) == -1) 16967ecd4f3SMax Laier return (-1); 17067ecd4f3SMax Laier 17167ecd4f3SMax Laier return (0); 17267ecd4f3SMax Laier } 17367ecd4f3SMax Laier 17467ecd4f3SMax Laier void 17567ecd4f3SMax Laier init_filter(char *opt_qname, int opt_verbose) 17667ecd4f3SMax Laier { 177ddd08375SKristof Provost struct pfctl_status *status; 17867ecd4f3SMax Laier 17967ecd4f3SMax Laier qname = opt_qname; 18067ecd4f3SMax Laier 18167ecd4f3SMax Laier if (opt_verbose == 1) 18267ecd4f3SMax Laier rule_log = PF_LOG; 18367ecd4f3SMax Laier else if (opt_verbose == 2) 18467ecd4f3SMax Laier rule_log = PF_LOG_ALL; 18567ecd4f3SMax Laier 186324fd7ecSKristof Provost pfh = pfctl_open(PF_DEVICE); 187324fd7ecSKristof Provost if (pfh == NULL) { 188324fd7ecSKristof Provost syslog(LOG_ERR, "can't pfctl_open()"); 189324fd7ecSKristof Provost exit(1); 190324fd7ecSKristof Provost } 1915824df8dSKristof Provost status = pfctl_get_status_h(pfh); 192ddd08375SKristof Provost if (status == NULL) { 19367ecd4f3SMax Laier syslog(LOG_ERR, "DIOCGETSTATUS"); 19467ecd4f3SMax Laier exit(1); 19567ecd4f3SMax Laier } 196ddd08375SKristof Provost if (!status->running) { 19767ecd4f3SMax Laier syslog(LOG_ERR, "pf is disabled"); 19867ecd4f3SMax Laier exit(1); 19967ecd4f3SMax Laier } 200ddd08375SKristof Provost 201ddd08375SKristof Provost pfctl_free_status(status); 20267ecd4f3SMax Laier } 20367ecd4f3SMax Laier 20467ecd4f3SMax Laier int 20567ecd4f3SMax Laier prepare_commit(u_int32_t id) 20667ecd4f3SMax Laier { 20767ecd4f3SMax Laier char an[PF_ANCHOR_NAME_SIZE]; 20867ecd4f3SMax Laier int i; 20967ecd4f3SMax Laier 21067ecd4f3SMax Laier memset(&pft, 0, sizeof pft); 21167ecd4f3SMax Laier pft.size = TRANS_SIZE; 21267ecd4f3SMax Laier pft.esize = sizeof pfte[0]; 21367ecd4f3SMax Laier pft.array = pfte; 21467ecd4f3SMax Laier 21567ecd4f3SMax Laier snprintf(an, PF_ANCHOR_NAME_SIZE, "%s/%d.%d", FTP_PROXY_ANCHOR, 21667ecd4f3SMax Laier getpid(), id); 21767ecd4f3SMax Laier for (i = 0; i < TRANS_SIZE; i++) { 21867ecd4f3SMax Laier memset(&pfte[i], 0, sizeof pfte[0]); 21967ecd4f3SMax Laier strlcpy(pfte[i].anchor, an, PF_ANCHOR_NAME_SIZE); 22067ecd4f3SMax Laier switch (i) { 22167ecd4f3SMax Laier case TRANS_FILTER: 22267ecd4f3SMax Laier pfte[i].rs_num = PF_RULESET_FILTER; 22367ecd4f3SMax Laier break; 22467ecd4f3SMax Laier case TRANS_NAT: 22567ecd4f3SMax Laier pfte[i].rs_num = PF_RULESET_NAT; 22667ecd4f3SMax Laier break; 22767ecd4f3SMax Laier case TRANS_RDR: 22867ecd4f3SMax Laier pfte[i].rs_num = PF_RULESET_RDR; 22967ecd4f3SMax Laier break; 23067ecd4f3SMax Laier default: 23167ecd4f3SMax Laier errno = EINVAL; 23267ecd4f3SMax Laier return (-1); 23367ecd4f3SMax Laier } 23467ecd4f3SMax Laier } 23567ecd4f3SMax Laier 236044243fcSKristof Provost if (ioctl(pfctl_fd(pfh), DIOCXBEGIN, &pft) == -1) 23767ecd4f3SMax Laier return (-1); 23867ecd4f3SMax Laier 23967ecd4f3SMax Laier return (0); 24067ecd4f3SMax Laier } 24167ecd4f3SMax Laier 24267ecd4f3SMax Laier int 24367ecd4f3SMax Laier prepare_rule(u_int32_t id, int rs_num, struct sockaddr *src, 24467ecd4f3SMax Laier struct sockaddr *dst, u_int16_t d_port, u_int8_t proto) 24567ecd4f3SMax Laier { 24667ecd4f3SMax Laier char an[PF_ANCHOR_NAME_SIZE]; 24767ecd4f3SMax Laier 24867ecd4f3SMax Laier if ((src->sa_family != AF_INET && src->sa_family != AF_INET6) || 24967ecd4f3SMax Laier (src->sa_family != dst->sa_family)) { 25067ecd4f3SMax Laier errno = EPROTONOSUPPORT; 25167ecd4f3SMax Laier return (-1); 25267ecd4f3SMax Laier } 25367ecd4f3SMax Laier 25467ecd4f3SMax Laier memset(&pfp, 0, sizeof pfp); 255e9eb0941SKristof Provost memset(&pfrule, 0, sizeof pfrule); 25667ecd4f3SMax Laier snprintf(an, PF_ANCHOR_NAME_SIZE, "%s/%d.%d", FTP_PROXY_ANCHOR, 25767ecd4f3SMax Laier getpid(), id); 25867ecd4f3SMax Laier strlcpy(pfp.anchor, an, PF_ANCHOR_NAME_SIZE); 259e9eb0941SKristof Provost strlcpy(pfanchor, an, PF_ANCHOR_NAME_SIZE); 26067ecd4f3SMax Laier 26167ecd4f3SMax Laier switch (rs_num) { 26267ecd4f3SMax Laier case PF_RULESET_FILTER: 263e9eb0941SKristof Provost pfticket = pfte[TRANS_FILTER].ticket; 26467ecd4f3SMax Laier break; 26567ecd4f3SMax Laier case PF_RULESET_NAT: 266e9eb0941SKristof Provost pfticket = pfte[TRANS_NAT].ticket; 26767ecd4f3SMax Laier break; 26867ecd4f3SMax Laier case PF_RULESET_RDR: 269e9eb0941SKristof Provost pfticket = pfte[TRANS_RDR].ticket; 27067ecd4f3SMax Laier break; 27167ecd4f3SMax Laier default: 27267ecd4f3SMax Laier errno = EINVAL; 27367ecd4f3SMax Laier return (-1); 27467ecd4f3SMax Laier } 275ba2a9207SKristof Provost if (pfctl_begin_addrs(pfh, &pfp.ticket)) 27667ecd4f3SMax Laier return (-1); 277e9eb0941SKristof Provost pfpool_ticket = pfp.ticket; 27867ecd4f3SMax Laier 27967ecd4f3SMax Laier /* Generic for all rule types. */ 280e9eb0941SKristof Provost pfrule.af = src->sa_family; 281e9eb0941SKristof Provost pfrule.proto = proto; 282e9eb0941SKristof Provost pfrule.src.addr.type = PF_ADDR_ADDRMASK; 283e9eb0941SKristof Provost pfrule.dst.addr.type = PF_ADDR_ADDRMASK; 28467ecd4f3SMax Laier if (src->sa_family == AF_INET) { 285e9eb0941SKristof Provost memcpy(&pfrule.src.addr.v.a.addr.v4, 28667ecd4f3SMax Laier &satosin(src)->sin_addr.s_addr, 4); 287e9eb0941SKristof Provost memset(&pfrule.src.addr.v.a.mask.addr8, 255, 4); 288e9eb0941SKristof Provost memcpy(&pfrule.dst.addr.v.a.addr.v4, 28967ecd4f3SMax Laier &satosin(dst)->sin_addr.s_addr, 4); 290e9eb0941SKristof Provost memset(&pfrule.dst.addr.v.a.mask.addr8, 255, 4); 29167ecd4f3SMax Laier } else { 292e9eb0941SKristof Provost memcpy(&pfrule.src.addr.v.a.addr.v6, 29367ecd4f3SMax Laier &satosin6(src)->sin6_addr.s6_addr, 16); 294e9eb0941SKristof Provost memset(&pfrule.src.addr.v.a.mask.addr8, 255, 16); 295e9eb0941SKristof Provost memcpy(&pfrule.dst.addr.v.a.addr.v6, 29667ecd4f3SMax Laier &satosin6(dst)->sin6_addr.s6_addr, 16); 297e9eb0941SKristof Provost memset(&pfrule.dst.addr.v.a.mask.addr8, 255, 16); 29867ecd4f3SMax Laier } 299e9eb0941SKristof Provost pfrule.dst.port_op = PF_OP_EQ; 300e9eb0941SKristof Provost pfrule.dst.port[0] = htons(d_port); 30167ecd4f3SMax Laier 30267ecd4f3SMax Laier switch (rs_num) { 30367ecd4f3SMax Laier case PF_RULESET_FILTER: 30467ecd4f3SMax Laier /* 30567ecd4f3SMax Laier * pass quick [log] inet[6] proto tcp \ 30667ecd4f3SMax Laier * from $src to $dst port = $d_port flags S/SAFR keep state 30767ecd4f3SMax Laier * (max 1) [queue qname] 30867ecd4f3SMax Laier */ 309e9eb0941SKristof Provost pfrule.action = PF_PASS; 310e9eb0941SKristof Provost pfrule.quick = 1; 311e9eb0941SKristof Provost pfrule.log = rule_log; 312e9eb0941SKristof Provost pfrule.keep_state = 1; 3135ee7cd21SMax Laier #ifdef __FreeBSD__ 314e9eb0941SKristof Provost pfrule.flags = (proto == IPPROTO_TCP ? TH_SYN : 0); 315e9eb0941SKristof Provost pfrule.flagset = (proto == IPPROTO_TCP ? 3165ee7cd21SMax Laier (TH_SYN|TH_ACK|TH_FIN|TH_RST) : 0); 3175ee7cd21SMax Laier #else 318e9eb0941SKristof Provost pfrule.flags = (proto == IPPROTO_TCP ? TH_SYN : NULL); 319e9eb0941SKristof Provost pfrule.flagset = (proto == IPPROTO_TCP ? 32067ecd4f3SMax Laier (TH_SYN|TH_ACK|TH_FIN|TH_RST) : NULL); 3215ee7cd21SMax Laier #endif 322e9eb0941SKristof Provost pfrule.max_states = 1; 32367ecd4f3SMax Laier if (qname != NULL) 324e9eb0941SKristof Provost strlcpy(pfrule.qname, qname, sizeof pfrule.qname); 32567ecd4f3SMax Laier break; 32667ecd4f3SMax Laier case PF_RULESET_NAT: 32767ecd4f3SMax Laier /* 32867ecd4f3SMax Laier * nat inet[6] proto tcp from $src to $dst port $d_port -> $nat 32967ecd4f3SMax Laier */ 330e9eb0941SKristof Provost pfrule.action = PF_NAT; 33167ecd4f3SMax Laier break; 33267ecd4f3SMax Laier case PF_RULESET_RDR: 33367ecd4f3SMax Laier /* 33467ecd4f3SMax Laier * rdr inet[6] proto tcp from $src to $dst port $d_port -> $rdr 33567ecd4f3SMax Laier */ 336e9eb0941SKristof Provost pfrule.action = PF_RDR; 33767ecd4f3SMax Laier break; 33867ecd4f3SMax Laier default: 33967ecd4f3SMax Laier errno = EINVAL; 34067ecd4f3SMax Laier return (-1); 34167ecd4f3SMax Laier } 34267ecd4f3SMax Laier 34367ecd4f3SMax Laier return (0); 34467ecd4f3SMax Laier } 34567ecd4f3SMax Laier 34667ecd4f3SMax Laier int 34767ecd4f3SMax Laier server_lookup(struct sockaddr *client, struct sockaddr *proxy, 34867ecd4f3SMax Laier struct sockaddr *server, u_int8_t proto) 34967ecd4f3SMax Laier { 35067ecd4f3SMax Laier if (client->sa_family == AF_INET) 35167ecd4f3SMax Laier return (server_lookup4(satosin(client), satosin(proxy), 35267ecd4f3SMax Laier satosin(server), proto)); 35367ecd4f3SMax Laier 35467ecd4f3SMax Laier if (client->sa_family == AF_INET6) 35567ecd4f3SMax Laier return (server_lookup6(satosin6(client), satosin6(proxy), 35667ecd4f3SMax Laier satosin6(server), proto)); 35767ecd4f3SMax Laier 35867ecd4f3SMax Laier errno = EPROTONOSUPPORT; 35967ecd4f3SMax Laier return (-1); 36067ecd4f3SMax Laier } 36167ecd4f3SMax Laier 36267ecd4f3SMax Laier int 36367ecd4f3SMax Laier server_lookup4(struct sockaddr_in *client, struct sockaddr_in *proxy, 36467ecd4f3SMax Laier struct sockaddr_in *server, u_int8_t proto) 36567ecd4f3SMax Laier { 36671d3c704SKristof Provost struct pfctl_natlook_key k = {}; 36771d3c704SKristof Provost struct pfctl_natlook r = {}; 36867ecd4f3SMax Laier 36971d3c704SKristof Provost k.direction = PF_OUT; 37071d3c704SKristof Provost k.af = AF_INET; 37171d3c704SKristof Provost k.proto = proto; 37271d3c704SKristof Provost memcpy(&k.saddr.v4, &client->sin_addr.s_addr, sizeof(k.saddr.v4)); 37371d3c704SKristof Provost memcpy(&k.daddr.v4, &proxy->sin_addr.s_addr, sizeof(k.daddr.v4)); 37471d3c704SKristof Provost k.sport = client->sin_port; 37571d3c704SKristof Provost k.dport = proxy->sin_port; 37667ecd4f3SMax Laier 37771d3c704SKristof Provost if (pfctl_natlook(pfh, &k, &r)) 37867ecd4f3SMax Laier return (-1); 37967ecd4f3SMax Laier 38067ecd4f3SMax Laier memset(server, 0, sizeof(struct sockaddr_in)); 38167ecd4f3SMax Laier server->sin_len = sizeof(struct sockaddr_in); 38267ecd4f3SMax Laier server->sin_family = AF_INET; 38371d3c704SKristof Provost memcpy(&server->sin_addr.s_addr, &r.daddr.v4, 38467ecd4f3SMax Laier sizeof server->sin_addr.s_addr); 38571d3c704SKristof Provost server->sin_port = r.dport; 38667ecd4f3SMax Laier 38767ecd4f3SMax Laier return (0); 38867ecd4f3SMax Laier } 38967ecd4f3SMax Laier 39067ecd4f3SMax Laier int 39167ecd4f3SMax Laier server_lookup6(struct sockaddr_in6 *client, struct sockaddr_in6 *proxy, 39267ecd4f3SMax Laier struct sockaddr_in6 *server, u_int8_t proto) 39367ecd4f3SMax Laier { 39471d3c704SKristof Provost struct pfctl_natlook_key k = {}; 39571d3c704SKristof Provost struct pfctl_natlook r = {}; 39667ecd4f3SMax Laier 39771d3c704SKristof Provost k.direction = PF_OUT; 39871d3c704SKristof Provost k.af = AF_INET6; 39971d3c704SKristof Provost k.proto = proto; 40071d3c704SKristof Provost memcpy(&k.saddr.v6, &client->sin6_addr.s6_addr, sizeof k.saddr.v6); 40171d3c704SKristof Provost memcpy(&k.daddr.v6, &proxy->sin6_addr.s6_addr, sizeof k.daddr.v6); 40271d3c704SKristof Provost k.sport = client->sin6_port; 40371d3c704SKristof Provost k.dport = proxy->sin6_port; 40467ecd4f3SMax Laier 40571d3c704SKristof Provost if (pfctl_natlook(pfh, &k, &r)) 40667ecd4f3SMax Laier return (-1); 40767ecd4f3SMax Laier 40867ecd4f3SMax Laier memset(server, 0, sizeof(struct sockaddr_in6)); 40967ecd4f3SMax Laier server->sin6_len = sizeof(struct sockaddr_in6); 41067ecd4f3SMax Laier server->sin6_family = AF_INET6; 41171d3c704SKristof Provost memcpy(&server->sin6_addr.s6_addr, &r.daddr.v6, 41267ecd4f3SMax Laier sizeof server->sin6_addr); 41371d3c704SKristof Provost server->sin6_port = r.dport; 41467ecd4f3SMax Laier 41567ecd4f3SMax Laier return (0); 41667ecd4f3SMax Laier } 417