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

Reply via email to