1/* $NetBSD: ipf.c,v 1.1 2005/04/03 22:15:32 peter Exp $ */
2
3/*
4 * ipf.c - NAT lookup code for IP Filter.
5 *
6 * This software is in the public domain.
7 * Written by Peter Postma <peter@NetBSD.org>
8 */
9
10#include <sys/cdefs.h>
11__RCSID("$NetBSD$");
12
13#include <sys/types.h>
14#include <sys/socket.h>
15#include <sys/ioctl.h>
16#include <sys/fcntl.h>
17
18#include <net/if.h>
19#include <netinet/in.h>
20#include <netinet/in_systm.h>
21#include <netinet/ipl.h>
22#include <netinet/ip_compat.h>
23#include <netinet/ip_fil.h>
24#include <netinet/ip_nat.h>
25
26#include <stdlib.h>
27#include <string.h>
28#include <syslog.h>
29#include <unistd.h>
30
31#include "identd.h"
32
33int
34ipf_natlookup(struct sockaddr_storage *ss, struct sockaddr *nat_addr,
35    int *nat_lport)
36{
37	natlookup_t nl;
38	ipfobj_t obj;
39	int dev;
40
41	(void)memset(&obj, 0, sizeof(obj));
42	(void)memset(&nl, 0, sizeof(nl));
43
44        /* Build the ipf object description structure. */
45	obj.ipfo_rev = IPFILTER_VERSION;
46	obj.ipfo_size = sizeof(nl);
47	obj.ipfo_ptr = &nl;
48	obj.ipfo_type = IPFOBJ_NATLOOKUP;
49
50	/* Build the ipf natlook structure. */
51	switch (ss[0].ss_family) {
52	case AF_INET:
53		(void)memcpy(&nl.nl_realip, &satosin(&ss[0])->sin_addr,
54		    sizeof(struct in_addr));
55		(void)memcpy(&nl.nl_outip, &satosin(&ss[1])->sin_addr,
56		    sizeof(struct in_addr));
57		nl.nl_realport = ntohs(satosin(&ss[0])->sin_port);
58		nl.nl_outport = ntohs(satosin(&ss[1])->sin_port);
59		nl.nl_flags = IPN_TCP | IPN_IN;
60		break;
61	case AF_INET6:
62		/* XXX IP Filter doesn't support IPv6 NAT yet. */
63	default:
64		maybe_syslog(LOG_ERR, "Unsupported protocol for NAT lookup "
65		    "(no. %d)", ss[0].ss_family);
66		return 0;
67	}
68
69	/* Open the NAT device and do the lookup. */
70	if ((dev = open(IPNAT_NAME, O_RDONLY)) == -1) {
71		maybe_syslog(LOG_ERR, "Cannot open %s: %m", IPNAT_NAME);
72		return 0;
73	}
74	if (ioctl(dev, SIOCGNATL, &obj) == -1) {
75		maybe_syslog(LOG_ERR, "NAT lookup failure: %m");
76		(void)close(dev);
77		return 0;
78	}
79	(void)close(dev);
80
81	/*
82	 * Put the originating address into nat_addr and fill
83	 * the port with the ident port, 113.
84	 */
85	switch (ss[0].ss_family) {
86	case AF_INET:
87		(void)memcpy(&satosin(nat_addr)->sin_addr, &nl.nl_inip,
88		    sizeof(struct in_addr));
89		satosin(nat_addr)->sin_port = htons(113);
90		satosin(nat_addr)->sin_len = sizeof(struct sockaddr_in);
91		satosin(nat_addr)->sin_family = AF_INET;
92		break;
93	case AF_INET6:
94		break;
95	}
96	/* Put the originating port into nat_lport. */
97	*nat_lport = nl.nl_inport;
98
99	return 1;
100}
101