ClearChain

Frox & PF

This article describes how to setup Frox to perform transparent proxying and caching via pf under FreeBSD.

Contents

 [hide]

  • 1 Background
  • 2 The Problem
  • 3 The Setup
  • 4 Frox PF Support
    • 4.1 Normal Connection (No transparent proxying)
    • 4.2 rdr connection (Transparent Proxying)
      • 4.2.1 With Squid backend
      • 4.2.2 Without Squid Backend
    • 4.3 Correcting the problem
  • 5 Installation
  • 6 Frox PF Transparent Proxy Patch
  • 7 Frox Config File

Background

Frox is a groovy little ftp-proxy which has the advantage of being able to cache the files that it proxies. Whilst there is lots of ftp proxies that help ftp through a firewall, frox is the only ftp-proxy I have found that supports caching of files.

Even better than that, Frox has the ability to use an external cache. Hence it’s possible to setup frox so it passes all ftp transfers to squid. This allows a dedicated cache (squid) to do the hard work with frox being merely a relay.

Frox also has the ability to transparently provide ftp proxying. Hence you can provide cached transparent ftp proxying without the users even knowing about it. This proves to be a great benefit in a lab where many people use ubuntu and often do apt-get update. The first user grabs the data, the second gets it from the cache.

The Problem

Sadly whilst frox has all these features, no on has really worked on it for a number of years. Hence somethings don’t work as well as expected. Take for instance the fact I wanted transparent proxying using pf the [OpenBSD] packet filter. Sadly frox doesn’t support pf.. till now

The Setup

I wanted a transparent ftp proxy setup which would use my existing squid setup in order to provide caching ftp. I use pf for my firewall (FreeBSD supports: ipfw, ipfilter and pf) so it had to work with my existing firewall setup.

Initially I setup frox-0.7.18 and tried with both ipfw and ipfilter options enable to get transparent redirects working. I setup the following pf rule to redirect to frox:

# Redirect to frox on port 2121
rdr on xl0 proto tcp from $local_net to any port 21 \
        -> $my_gatewaybox port 2121

and the frox config file as given below. Sadly frox kept replying

421 Proxy tried to loop. Closing connection

I tried lots of things to no avail to fix this. Finally I sat down and looked at the code.

Frox PF Support

It turns out that frox was complaining about the loop due to the destination address being the localhost/gateway box rather than actual ftp server we wanted to contact. This was due to the pf redirect. Basically the following happens:

Normal Connection (No transparent proxying)

internalhost -> frox -> <tooltip>XQXFTPXQX|XQXFile Transport ProtocolXQX</tooltip> Server

Frox gets a connection request:

Connect:

All is good

rdr connection (Transparent Proxying)

With Squid backend

internalhost -+ rdr
              |
              +- ftp-proxy (gateway box)
                      |
                      | External Cache (ie squid) -> Ftp Server

Frox gets a connection request:

Connect:

Without Squid Backend

internalhost -+ rdr        +-> <tooltip>XQXFTPXQX|XQXFile Transport ProtocolXQX</tooltip> Server
              |            |
              +- ftp-proxy +
                      |
                      | Frox Internal cache

Frox gets a connection request: Connect:

Correcting the problem

Now the problem is simple. Frox never sees the ftp server address that the client intended to visit if we use the pf redirect. For ipfw, this is not the issue you can use something like:

ipfw fwd INTERNALGWADDRESS,2121 tcp from INTERNALNETWORK to any dst-port 21 out keep-state

and ipfw only does the redirect on the ‘out’ traffic. Hence frox sees valid information for the ftp server.

IPFilter works as in bsd.c frox has code that asks ipfilter for the external address. But frox has no code to do the same for pf.

Hence I worked on the code to provide the same functionality to frox for pf. The below patch is what I came up with and it works!

Installation

To use this code:

Now your done, you can use a rule like:

# Redirect to frox on port 2121
rdr on xl0 proto tcp from $local_net to any port 21 \
        -> $my_gatewaybox port 2121

in pf.conf, and load the rule with pfctl -f pf.conf to make it work.

How you set frox running is up to you!

Hope this helps someone. —Benjsc 10:25, 23 May 2007 (EIT)

 

Frox PF Transparent Proxy Patch

The following patch allows frox to be used as a transparent ftp proxy with the OpenBSD pf packet filter.

The full patch is available at http://www.clearchain.com/~benjsc/download/frox/pf.patch

--- bsd.c.orig  Fri Feb  4 20:54:55 2005
+++ bsd.c       Wed Jul 25 01:25:16 2007
@@ -30,6 +30,16 @@
 #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>
@@ -51,6 +61,11 @@
        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;
 }

@@ -61,6 +76,11 @@
 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;
@@ -99,6 +119,31 @@
                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;

Frox Config File

The config file to use Frox as a transparent ftp proxy with pf.

# $ClearChain: machines/aquila/usr/local/etc/frox.conf,v 1.2 2006/05/23 11:29:15 benjsc Exp $
# Configuration file for frox transparent ftp-proxy.

# Send SIGHUP after editing and it will be reread. This will fail
# completely if we are chrooted and the config file isn't within the
# dir we have chrooted to, or if we have dropped priveleges and no
# longer have permission to read the config file! Some options cannot
# be reread - namely those which require special privelidges (ie.
# BindToDevice, Listen, Port, TransparentData) and the caching stuff.

####################################################################
# Network Options                                                  #
####################################################################

# Address to listen on - default is 0.0.0.0 If you are using an OS other
# than Linux and are doing transparent proxying then you will need to set
# this to the IP of a local interface. If using linux you could leave it
# commented out to listen on all local IPs.
#
# Listen firewall.localnet
# Change it with your ip!
Listen 192.168.154.1

# Port to listen on. Must be supplied.
#
Port 2121

# Whether to run from inetd. You should still define Port above, but
# it isn't used for much.
#
# FromInetd yes

# Stop frox from putting itself into the background. Use this if you want
# to run frox from supervise from djb's daemontools
#
#NoDetach yes

# A hack that should allow you to get away without putting resolver libraries
# into the chroot jail. The default is fine unless for some reason you have
# this hostname in /etc/hosts. If this sort of thing offends you, you may
# comment this out and copy resolver libraries into the chroot jail instead.
# See FAQ section 3.2 for details.
#
#ResolvLoadHack wontresolve.doesntexist.abc

# Another ftp proxy to forward on to. Frox will contact this ftp
# proxy, and send it a login name of the form "user@host:port" where
# host and port are the server frox should contact. If you set
# FTPProxyNoPort then frox will send logins of the form user@host
#
# FTPProxy 192.168.2.9:2222
# FTPProxyNoPort yes

# Pick the IP frox should use for outgoing connections. You probably don't
# need this, and it is not well tested.
#
#TcpOutgoingAddr 192.168.154.1

# Pick the IP that frox should send in PASV replies to the client. Defaults
# to the address frox received the control connection on which you shouldn't
# need to change unless you are doing NAT between frox and your clients, or
# are trying to tunnel connections using frox. See FAQ.
#
#PASVAddress 192.168.0.2

####################################################################
# General Options                                                  #
####################################################################
# User and group to drop priveliges to. This must be specified - if
# you really want to run as root (not a good idea) you must say so
# specifically, and have compiled with --enable-run-as-root.
#
User nobody
Group nogroup

# This is frox's working directory - it must be specified. Temporary
# files and sockets will be created here. If you are using local
# caching then the cache will be stored in this directory too. It
# should be owned by frox with permissions 700. By default frox will
# also chroot to this dir on startup. To avoid this you must specifically
# set DontChroot to Yes.
#
WorkingDir /tmp
DontChroot Yes

# Logging level. 0=No logging. 5=Critical errors only. 10= All errors.
# 15=Errors, other important stuf. 20= Errors, connections, cache
# hits/misses 25=Debug info including text of control session. By
# default frox will log through syslog as facility daemon. If you want
# frox to log to a file instead specify this in LogFile below. You may
# set LogFile to "stderr" if you wish it to log there. XferLogging
# defaults to on, and results in a one line log entry for each file
# transferred irrespective of the log level. You can turn this off
# below.
#
# LogFile /tmp/frox.log
# XferLogging no
#LogLevel 15

# File to store PID in. Default is not to. If this file is not within
# the Chroot directory then it cannot be deleted on exit, but will
# otherwise work fine.
#
PidFile /var/run/frox.pid

####################################################################
# Ftp Protocol Options                                             #
####################################################################

# Active --> Passive conversion. If set then all outgoing connections
# from the proxy will be passive <tooltip>XQXFTPXQX|XQXFile Transport ProtocolXQX</tooltip>, regardless of the type of the
# connection coming in. This makes firewalling a lot easier. Defaults
# to no.
#
APConv yes

# Passive --> Active conversion. If set then all outgoing connections
# from the proxy will be active <tooltip>XQXFTPXQX|XQXFile Transport ProtocolXQX</tooltip>, regardless of the type of the
# connection coming in. Defaults to no.
# DO NOT USE WITH APConv!
#
#PAConv yes

# Block PORT commands asking data to be sent to ports<1024 and
# prevent incoming control stream connections from port 20 to
# help depend against ftp bounce attacks. Defaults to on.
#
BounceDefend yes

# If true then only accept data connections from the hosts the control
# connections are to. Breaks the rfc, and defaults to off.
#
# SameAddress yes

# Normally frox strips out nonprintable characters from the control
# stream. This makes buffer overflow attacks on clients/servers much more
# difficult. If you download files that contain non english characters
# this may cause you problems (especially for big charsets like Chines).
# In that case turn on this option.
#
# AllowNonASCII yes

# Try to transparently proxy the data connections as well. Not
# necessary for most clients, and does increase security risks. N.V.
# You probably do _NOT_ need this option. It increases the complexity
# of what frox has to do, increases the difficulty of setting frox up
# correctly, and increases potential security risks. This has nothing
# to do with whether your clients will be transparently proxied. If
# you still want to use this option then read README.transdata for
# details.
#
# TransparentData yes

# Specify ranges for local ports to use for outgoing connections and
# for sending out in PORT commands. By default these are all between
# 40000 and 50000, but you might want to split them up if you have
# complicated firewalling rules.
#
# ControlPorts 40000-40999
# PassivePorts 41000-41999
# ActivePorts  42000-42999

# SSL/AUTH support. Frox must have been linked to the openssl libraries.
# This is currently experimental, and only tested against vsftpd
#
# UseSSL yes
# DataSSL no

####################################################################
# Caching Options                                                  #
####################################################################

# Caching options. There should be at most one CacheModule line, and
# Cache lines to give the options for that caching module. CacheModule
# is <tooltip>XQXHTTPXQX|XQXHyperText Transfer ProtocolXQX</tooltip> (rewrites ftp requests as <tooltip>XQXHTTPXQX|XQXHyperText Transfer ProtocolXQX</tooltip> and sends them to a <tooltip>XQXHTTPXQX|XQXHyperText Transfer ProtocolXQX</tooltip>
# proxy like squid), or local (cache files locally). The relevant
# module needs to have been compiled in at compile time. See FAQ for
# details. If there are no CacheModule lines then no caching will be
# done. "CacheModule None" explicitly requests no caching, and is
# useful to turn off caching within a subsection (below).
#
# CacheModule local
# CacheSize 400
#
CacheModule http
HTTPProxy 127.0.0.1:3128

# MinCacheSize 65536
# ForceHTTP no  # Set to yes to force http file retreiving even if
#               # file is not cacheable
#
# StrictCaching no  # Read FAQ for details.
# CacheOnFQDN yes   # Read FAQ for details.
#
# CacheAll no   # Set to yes to cache non anonymous ftp downloads

# Virus scanning -- see FAQ
#
# VirusScanner '"/usr/bin/viruscan" "--option" "%s"'
# VSOK 0
# VSProgressMsgs 30

####################################################################
# Access control                                                   #
####################################################################

# Allow non-transparent proxying support. The user can connect
# directly to frox, and give his username as user@host:port or
# user@host. Defaults to no. NTPAddress gives the address to which
# incoming connections must be addressed if the client is to be offered
# non-transparent proxying. For most people using this it will be the same
# as the Listen address above. If not given then all connections will be
# offered non transparent proxying. If you are not using transparent
# proxying at all then you should leave NTPAddress commented out.
#
#DoNTP yes
#NTPAddress 192.168.155.1:2121

# Number of seconds of no activity before closing session
# Defaults to 300
#
# Timeout 300

#Maximum number of processes to fork.
#
# MaxForks 0 # For debugging -- only one connection may be served.
MaxForks 10

# Maximum number of connections from a single host (IP address).
MaxForksPerHost 4

# Maximum number of bytes/second to be transferred over the data
# connection for each client. MaxTransferRate limits downloads and
# MaxUploadRate uploads. CacheDlRate is the rate for downloads of files
# that are cached locally - if not set these files will be downloaded at
# full speed.
#
# MaxTransferRate 4096
# CacheDlRate 8192
# MaxUploadRate 4096

# Access control lists:
# The format is: "ACL Allow|Deny SRC - DST [PORTS]"
# a dns name, or * to match everything.
#
# PORTS is a list of ports. If specified then the rule will only match
# if the destination port of the connection is in this list. This is
# likely only relevant if you are allowing non-transparent proxying of
# ftp connections (ie. DoNTP is enabled above). Specifying * is equivalent
# to not specifying anything - all ports will be matched
#
# Any connection that matches no rules will be denied. Since there are
# no rules by default you'll need to add something to let any
# connections happen at all (look at the last example if you are
# feeling lazy/not bothered by security).
#
# # Examples:
# # Allow local network to ftp to port 21 only, and block host ftp.evil
# ACL Deny * - ftp.evil
# ACL Allow 192.168.0.0/255.255.0.0 - * 21
#
# # Allow local network to ftp anywhere except certain dodgy ports. Network
# # admin's machine can ftp anywhere.
# ACL Allow admin.localnet - *
# ACL Deny * - * 1-20,22-1024,6000-6007,7100
# ACL Allow 192.168.0.0/16 - * *
#
# # You don't really believe in this security stuff, and just want
# # everything to work.
ACL Allow * - *

# Command control program: A bit like the idea of a squid redirector.
# By default the old interface is used so as not to break existing
# installations. The new interface is much more powerful, and is
# reccommended for new scripts -- set UseOldCCP to false to use it.
# See the FAQ for details.
#
# CCProgram /usr/local/lib/frox/bin/ccp
# UseOldCCP no

####################################################################
# Subsections                                                      #
####################################################################
# Matching rules the same as ACLS. Only some options can be specified
# in a subsection (currently the yes/no options, timeout, and caching
# options).
#
# SubSection * - ftp.dodgy.server
#  StrictCaching yes
# EndSection
#
# SubSection * - 10.0.0.0/24 # A low latency high bandwidth connection
#  MinCacheSize 4096
# EndSection
#
# Subsection * - ftp.localnetwork
# # To disable caching if it has been turned on in a parent section
#  CacheModule None
# EndSection
Exit mobile version