1 1.3 christos /* $NetBSD: pf.c,v 1.3 2016/12/10 05:43:11 christos Exp $ */ 2 1.1 peter 3 1.1 peter /* 4 1.1 peter * pf.c - NAT lookup code for pf. 5 1.1 peter * 6 1.1 peter * This software is in the public domain. 7 1.1 peter * Written by Peter Postma <peter (at) NetBSD.org> 8 1.1 peter */ 9 1.1 peter 10 1.2 peter #include <sys/cdefs.h> 11 1.3 christos __RCSID("$NetBSD: pf.c,v 1.3 2016/12/10 05:43:11 christos Exp $"); 12 1.2 peter 13 1.1 peter #include <sys/types.h> 14 1.1 peter #include <sys/socket.h> 15 1.1 peter #include <sys/ioctl.h> 16 1.1 peter #include <sys/fcntl.h> 17 1.1 peter 18 1.1 peter #include <net/if.h> 19 1.1 peter #include <netinet/in.h> 20 1.1 peter #include <net/pfvar.h> 21 1.1 peter 22 1.1 peter #include <stdlib.h> 23 1.1 peter #include <string.h> 24 1.1 peter #include <syslog.h> 25 1.1 peter #include <unistd.h> 26 1.1 peter 27 1.1 peter #include "identd.h" 28 1.1 peter 29 1.1 peter int 30 1.3 christos pf_natlookup(const struct sockaddr_storage *ss, 31 1.3 christos struct sockaddr_storage *nat_addr, in_port_t *nat_lport) 32 1.1 peter { 33 1.1 peter struct pfioc_natlook nl; 34 1.1 peter int dev; 35 1.1 peter 36 1.1 peter (void)memset(&nl, 0, sizeof(nl)); 37 1.1 peter 38 1.1 peter /* Build the pf natlook structure. */ 39 1.1 peter switch (ss[0].ss_family) { 40 1.1 peter case AF_INET: 41 1.3 christos (void)memcpy(&nl.daddr.v4, &csatosin(&ss[0])->sin_addr, 42 1.1 peter sizeof(struct in_addr)); 43 1.3 christos (void)memcpy(&nl.saddr.v4, &csatosin(&ss[1])->sin_addr, 44 1.1 peter sizeof(struct in_addr)); 45 1.3 christos nl.dport = csatosin(&ss[0])->sin_port; 46 1.3 christos nl.sport = csatosin(&ss[1])->sin_port; 47 1.1 peter nl.af = AF_INET; 48 1.1 peter nl.proto = IPPROTO_TCP; 49 1.1 peter nl.direction = PF_IN; 50 1.1 peter break; 51 1.1 peter case AF_INET6: 52 1.3 christos (void)memcpy(&nl.daddr.v6, &csatosin6(&ss[0])->sin6_addr, 53 1.1 peter sizeof(struct in6_addr)); 54 1.3 christos (void)memcpy(&nl.saddr.v6, &csatosin6(&ss[1])->sin6_addr, 55 1.1 peter sizeof(struct in6_addr)); 56 1.3 christos nl.dport = csatosin6(&ss[0])->sin6_port; 57 1.3 christos nl.sport = csatosin6(&ss[1])->sin6_port; 58 1.1 peter nl.af = AF_INET6; 59 1.1 peter nl.proto = IPPROTO_TCP; 60 1.1 peter nl.direction = PF_IN; 61 1.1 peter break; 62 1.1 peter default: 63 1.1 peter maybe_syslog(LOG_ERR, "Unsupported protocol for NAT lookup " 64 1.1 peter "(no. %d)", ss[0].ss_family); 65 1.1 peter return 0; 66 1.1 peter } 67 1.1 peter 68 1.1 peter /* Open the /dev/pf device and do the lookup. */ 69 1.1 peter if ((dev = open("/dev/pf", O_RDWR)) == -1) { 70 1.1 peter maybe_syslog(LOG_ERR, "Cannot open /dev/pf: %m"); 71 1.1 peter return 0; 72 1.1 peter } 73 1.1 peter if (ioctl(dev, DIOCNATLOOK, &nl) == -1) { 74 1.1 peter maybe_syslog(LOG_ERR, "NAT lookup failure: %m"); 75 1.1 peter (void)close(dev); 76 1.1 peter return 0; 77 1.1 peter } 78 1.1 peter (void)close(dev); 79 1.1 peter 80 1.1 peter /* 81 1.1 peter * Put the originating address into nat_addr and fill 82 1.1 peter * the port with the ident port, 113. 83 1.1 peter */ 84 1.1 peter switch (ss[0].ss_family) { 85 1.1 peter case AF_INET: 86 1.1 peter (void)memcpy(&satosin(nat_addr)->sin_addr, &nl.rsaddr.v4, 87 1.1 peter sizeof(struct in_addr)); 88 1.1 peter satosin(nat_addr)->sin_port = htons(113); 89 1.1 peter satosin(nat_addr)->sin_len = sizeof(struct sockaddr_in); 90 1.1 peter satosin(nat_addr)->sin_family = AF_INET; 91 1.1 peter break; 92 1.1 peter case AF_INET6: 93 1.1 peter (void)memcpy(&satosin6(nat_addr)->sin6_addr, &nl.rsaddr.v6, 94 1.1 peter sizeof(struct in6_addr)); 95 1.1 peter satosin6(nat_addr)->sin6_port = htons(113); 96 1.1 peter satosin6(nat_addr)->sin6_len = sizeof(struct sockaddr_in6); 97 1.1 peter satosin6(nat_addr)->sin6_family = AF_INET6; 98 1.1 peter break; 99 1.1 peter } 100 1.1 peter /* Put the originating port into nat_lport. */ 101 1.1 peter *nat_lport = nl.rsport; 102 1.1 peter 103 1.1 peter return 1; 104 1.1 peter } 105