/***************************************
This is part of frox: A simple transparent FTP proxy
Copyright (C) 2000 James Hollingshead
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
bsd.c -- Bsd specific code. Should contain transparent proxy code,
but currently only non transparent proxying works. Thanks
to Sergey Matveychuk for getting frox running on bsd.
***************************************/
#include "common.h"
#include "os.h"
#ifdef TRANS_DATA
#error --enable-transparent-data not supported under BSD
#endif
#ifdef PF
#include <fcntl.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <net/pfvar.h>
static int natfd;
#endif
#ifdef IPFILTER
#include <fcntl.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/ip_compat.h>
#include <netinet/ip_fil.h>
#include <netinet/ip_nat.h>
static int natfd;
#endif
/* This is called before priveliges are dropped or we chroot(). For
* ipfilter opening the fd for get_orig_dest is a priveliged operation
* so we do it here. */
int os_init(void)
{
#ifdef IPFILTER
natfd = open(IPL_NAME, O_RDONLY, 0);
if(natfd < 0)
write_log(ERROR, "Unable to initialise IPFilter");
#endif
#ifdef PF
natfd = open("/dev/pf", O_RDWR);
if (natfd == -1)
write_log(ERROR, "Unable to initialise PF");
#endif
return 0;
}
/* ------------------------------------------------------------- **
** Get the original destination address of a transparently proxied
** socket.
** ------------------------------------------------------------- */
int get_orig_dest(int fd, struct sockaddr_in *addr)
{
socklen_t len;
#ifdef PF
struct pfioc_natlook nl;
struct sockaddr_in from;
int r2;
#endif
#ifdef IPFILTER
struct natlookup nat;
struct sockaddr_in from;
int r2;
#endif
struct sockaddr_in to;
int r1;
len = sizeof(*addr);
r1 = getsockname(fd, (struct sockaddr *) &to, &len);
#ifdef IPFILTER
/* Look for ipfilter first */
getpeername(fd, (struct sockaddr *) &from, &len);
nat.nl_inport = to.sin_port;
nat.nl_outport = from.sin_port;
nat.nl_inip = to.sin_addr;
nat.nl_outip = from.sin_addr;
nat.nl_flags = IPN_TCP;
r2 = -1;
if(natfd > 0) {
/* Check SIOCGNATL to find out ipfilter version (taken from squid) */
if(63 == (SIOCGNATL & 0xff)) {
struct natlookup *nlp = &nat;
r2 = ioctl(natfd, SIOCGNATL, &nlp);
} else
r2 = ioctl(natfd, SIOCGNATL, &nat);
}
if(r2 == 0) { /*Successful with ipfilter - copy address across */
memset(addr, sizeof(*addr), 0);
addr->sin_addr.s_addr = nat.nl_realip.s_addr;
addr->sin_port = nat.nl_realport;
addr->sin_family = AF_INET;
return r2;
}
#endif
#ifdef PF
getpeername(fd, (struct sockaddr *) &from, &len);
memset(&nl, 0, sizeof(struct pfioc_natlook));
memcpy( &nl.daddr.v4, &to.sin_addr.s_addr, sizeof( nl.saddr.v4 ));
memcpy( &nl.saddr.v4, &from.sin_addr.s_addr, sizeof( nl.daddr.v4 ));
nl.dport = to.sin_port;
nl.sport = from.sin_port;
nl.af = AF_INET;
nl.proto = IPPROTO_TCP;
nl.direction = PF_INOUT;
if ( natfd > 0 ){
if (ioctl(natfd, DIOCNATLOOK, &nl)==-1){
write_log(ERROR, "Failed to lookup address");
}
else {
memset(addr, sizeof(*addr), 0);
memcpy(&addr->sin_addr.s_addr, &nl.rdaddr.v4.s_addr, sizeof(struct sockaddr_in));
addr->sin_len = sizeof(struct sockaddr_in);
addr->sin_port = nl.rdport;
addr->sin_family = AF_INET;
return r2;
}
}
#endif
memcpy(addr, &to, len);
return r1;
}
/* ------------------------------------------------------------- **
** Get the address of the interface we connect to the client through
** for putting in our 227 reply. We insist that the user has Listen
** defined in his config file, and use that address.
** ------------------------------------------------------------- */
int get_local_address(const int fd, struct sockaddr_in *addr)
{
socklen_t len;
*addr = config.listen_address;
if(addr->sin_addr.s_addr != 0) {
addr->sin_port = 0;
return (0);
}
len = sizeof(*addr);
return (getsockname(fd, (struct sockaddr *) addr, &len));
}
int bindtodevice(int fd)
{
if(!config.device)
return (0);
write_log(ERROR, "Bind to device not supported in BSD");
return (-1);
}
syntax highlighted by Code2HTML, v. 0.9.1