We have a little transparent proxy we wrote for POP. It is in Perl, but
it uses a little Perl XS module to do the ioctl on /dev/ipnat to figure
out the real destination address. The code originally came from Squid,
and has that part to see if the "newer" version of the ioctl command is
required (for the record, in this case, it shows up as required).
We've used this code on OpenBSD 2.9 boxes with various versions of
IPFilter, up to around 3.4.26 (I'm not currently positive of that last
working version, I can get it later if needed.)
Recently, we've tried to make an OpenBSD 3.1 box that does the same
thing. We start with OpenBSD 3.1, then cvs update to make sure we have
stable, then patch 3.4.29 into it. Then, we recompile our Perl module,
and start things up...and it doesn't work. The ioctl call fails, and we
get a "perl: SIOCGNATL failed: No such process", the "No such process"
being what comes from errno.
Any ideas? I'm at a loss here. I'm currently building an OpenBSD 3.1
with IPFilter 3.4.28, to see if that helps.
Attached is my Perl XS code, but it is really similar to Squid's
(changes basically amount to returning the value to perl). I ignore the
port because I know what port it is, as my rule sets that up:
rdr fxp0 0.0.0.0/0 port pop3 -> 127.0.0.1 port 1110
(BTW, in my Perl XS code, you'll see a VerifyPermissions function. This
is called by the proxy at first to make sure it has enough permissions.
It passes...meaning permissions aren't the problem.)
Thanks for any help...I really don't know where to go next.
Kevin
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include <sys/ioctl.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <syslog.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <net/if.h>
#include <netinet/tcp.h>
#include <netinet/ip_compat.h>
#include <netinet/ip_fil.h>
#include <netinet/ip_nat.h>
#include <netinet/ip_state.h>
#include <netinet/ip_proxy.h>
#include <netinet/ip_nat.h>
/* Copyright (c) 2001 Secure Interiors, Inc. All rights reserved. */
/* $Id: GetNATIP.xs,v 1.8 2002/02/01 20:08:00 kwhite Exp $ */
MODULE = SI::GetNATIP PACKAGE = SI::GetNATIP
int
LookupCallingIP(fd)
int fd
PPCODE:
struct sockaddr_in laddr, faddr;
struct natlookup natlookup;
int slen, natfd;
char static *s_hostname;
u_int16_t serverport;
int error_num = 0;
int x;
static int siocgnatl_cmd = SIOCGNATL & 0xff;
bzero((char *)&laddr, sizeof(laddr));
bzero((char *)&faddr, sizeof(faddr));
slen = sizeof(laddr);
if (getsockname(fd, (struct sockaddr *)&laddr, &slen) < 0)
{
error_num = -1;
}
else
{
slen = sizeof(faddr);
if (getpeername(fd, (struct sockaddr *)&faddr, &slen) < 0)
{
error_num = -1;
}
else
{
natlookup.nl_inport = ntohs(laddr.sin_port);
natlookup.nl_outport = ntohs(faddr.sin_port);
natlookup.nl_inip = laddr.sin_addr;
natlookup.nl_outip = faddr.sin_addr;
natlookup.nl_flags = IPN_TCP;
if ((natfd = open(IPL_NAT, O_RDONLY)) < 0)
{
error_num = -1;
}
else
{
if (63 == siocgnatl_cmd)
{
struct natlookup *nlp = &natlookup;
syslog(LOG_ERR, "New way");
x = ioctl(natfd, SIOCGNATL, &nlp);
}
else
{
syslog(LOG_ERR, "Old way");
x = ioctl(natfd, SIOCGNATL, &natlookup);
}
if (x == -1)
{
syslog(LOG_ERR, "SIOCGNATL failed: %m\n");
close(natfd);
error_num = -2;
}
else
{
close(natfd);
s_hostname = (char *) inet_ntoa(natlookup.nl_realip);
serverport = ntohs(natlookup.nl_realport);
/* printf("%s: %d\n", s_hostname, serverport); */
}
}
}
}
if (error_num != 0)
{
XPUSHs(sv_2mortal(newSVnv(error_num)));
if (error_num == -2)
{
XPUSHs(sv_2mortal(newSVpv(strerror(errno), 0)));
}
}
else
{
XPUSHs(sv_2mortal(newSVpv(s_hostname, 0)));
XPUSHs(sv_2mortal(newSVnv(serverport)));
}
int
VerifyPermissions()
CODE:
int natfd;
if ((natfd = open(IPL_NAT, O_RDONLY)) < 0)
{
RETVAL = 0;
}
else
{
RETVAL = 1;
close(natfd);
}
OUTPUT:
RETVAL