#!/bin/sh # called from /usr/local/etc/if-local # 1999.02.13 kjw - this script is called by both ppp and pcmcia to setup # resolv.conf, maybe more in the near future. dhcp?? # USAGE: $0 (preup|up|down) $LOCATION $INTERFACE $IP # LOCATION=BluetoothDialup|...(see if-local) # INTERFACE=eth*|ppp* ######################################################################### ## begin subroutines ## pick_dns_ip() { # Purpose: allocate a unique localhost IP for a DNS cache # Args: $LOCATION # Returns on stdout: ip address like 127.0.0.5 # Returns on stdout: 127.0.0.254 for an unknown location. Conflicts probable # These ip addresses must be unique and unchanging, unless you're good # enough to clean up the old dnscaches that may reside on disk case $LOCATION in BluetoothDialup) echo "127.0.0.3" ;; *) $LOGGER "ERROR: unknown location $LOCATION in pick_dns_ip()" echo "127.0.0.254" ;; esac } make_resolv_conf() { # requires: $LOCATION $DOMAIN $NAMESERVER # optional: $SEARCHLIST $NAMESERVER2 $NAMESERVER3 $NAMESERVER4 # Why one cache per location? Because a internal corporate dns server # might give you a different ip address for www.company.com rm -f /etc/resolv.conf.saved if [ -f /etc/resolv.conf ] ; then if [ "`head -1 /etc/resolv.conf | cut -f1 -d=`" != "# LOCATION=" ] ; then # if it's not one of our generated resolv.conf's, save it mv -f /etc/resolv.conf /etc/resolv.conf.saved fi fi if [ -x /usr/local/bin/dnscache ] ; then DNSCACHE_IP=`pick_dns_ip $LOCATION` DNSCACHE_SUBNET=`echo $DNSCACHE_IP | cut -f1-3 -d.` DNSCACHE_NAME="dnscache-$DNSCACHE_SUBNET-$LOCATION" $LOGGER "setting up /etc/resolv.conf -> $DNSCACHE_NAME -> $NAMESERVER" # install dnscache if needed if [ ! -d /etc/$DNSCACHE_NAME ] ; then /usr/local/bin/dnscache-conf dnscache dnslog /etc/$DNSCACHE_NAME $DNSCACHE_IP touch /etc/$DNSCACHE_NAME/root/ip/$DNSCACHE_IP touch /etc/$DNSCACHE_NAME/root/ip/127.0.0.1 else /usr/local/bin/svc -d /etc/$DNSCACHE_NAME fi # configure forwarding cache echo "$NAMESERVER" >/etc/$DNSCACHE_NAME/root/servers/@ chmod a+r /etc/$DNSCACHE_NAME/root/servers/@ echo 1 >/etc/$DNSCACHE_NAME/env/FORWARDONLY # activate forwarding cache. svscan should start it in a few seconds. ln -sf /etc/$DNSCACHE_NAME /service/. # configure system echo "# LOCATION=$LOCATION" >/etc/resolv.conf echo "nameserver $DNSCACHE_IP" >>/etc/resolv.conf echo "search $DOMAIN" >>/etc/resolv.conf chmod a+r /etc/resolv.conf if dnsip www.google.com >/dev/null || \ dnsip www.yahoo.com >/dev/null || \ dnsip www.microsoft.com >/dev/null || \ dnsip www.ibm.com >/dev/null || \ dnsip www.google.com >/dev/null || \ dnsip www.yahoo.com >/dev/null || \ dnsip www.microsoft.com >/dev/null || \ dnsip www.ibm.com >/dev/null ; then # at least one lookup succeeded $LOGGER "dnscache verified" return else # dnscache not working? failover to plain resolv.conf /usr/local/bin/svc -d /etc/$DNSCACHE_NAME $LOGGER "dnscache not resolving! failover to plain resolv.conf" fi fi #else $LOGGER "setting up /etc/resolv.conf -> $NAMESERVER" echo "# LOCATION=$LOCATION" >/etc/resolv.conf echo "domain $DOMAIN" >>/etc/resolv.conf echo "nameserver $NAMESERVER" >>/etc/resolv.conf [ -n "$NAMESERVER2" ] && echo "nameserver $NAMESERVER2">>/etc/resolv.conf [ -n "$NAMESERVER3" ] && echo "nameserver $NAMESERVER3">>/etc/resolv.conf [ -n "$NAMESERVER4" ] && echo "nameserver $NAMESERVER4">>/etc/resolv.conf [ -n "$SEARCHLIST" ] && echo "search $SEARCHLIST" >>/etc/resolv.conf chmod a+r /etc/resolv.conf return } remove_resolv_conf() { # requires: $LOCATION $DOMAIN $NAMESERVER # optional: $NAMESERVER2 $SEARCHLIST DNSCACHE_IP=`pick_dns_ip $LOCATION` DNSCACHE_SUBNET=`echo $DNSCACHE_IP|cut -f1-3 -d.` DNSCACHE_NAME=dnscache-$DNSCACHE_SUBNET-$LOCATION if [ -d /service/$DNSCACHE_NAME ] ; then $LOGGER "Turning off dnscache running on $DNSCACHE_IP" /usr/local/bin/svc -dx /service/$DNSCACHE_NAME # turn it off! sleep 1 /usr/local/bin/svc -dx /service/$DNSCACHE_NAME/log # turn it off! rm /service/$DNSCACHE_NAME # even for reboots if [ -f '/etc/resolv.conf.saved' ] ; then mv -f /etc/resolv.conf.saved /etc/resolv.conf fi #fgrep -v "search $DOMAIN" /etc/resolv.conf.N #mv -f /etc/resolv.conf.N /etc/resolv.conf else if [ "x`head -1 /etc/resolv.conf`" = "x# LOCATION=$LOCATION" ] ; then rm -f /etc/resolv.conf # restore previous resolv.conf if [ -f '/etc/resolv.conf.saved' ] ; then mv -f /etc/resolv.conf.saved /etc/resolv.conf fi fi fi return } install_external_dnat() { # IF=eth0|ppp0... interface # IP=ip address of the local interface # DNAT_DEST=ip address to fwd incomming tcp connections to # DNAT_PORT=port (both external and internal) IF=$1 IP=$2 DNAT_DEST=$3 DNAT_PORT=$4 _TCP="--protocol tcp" #_INTF_IN="--in-interface $IF" _DEST='--destination' _DPORT="--destination-port $DNAT_PORT" _DNAT_DEST="--to-destination $DNAT_DEST" # FEATURE: DNAT outside to inside tcp port forwarding #iptables -t nat -I PREROUTING 1 $_TCP $_INTF_IN $_DEST $IP $_DPORT --jump DNAT $_DNAT_DEST iptables -t nat -I PREROUTING 1 $_TCP $_DEST $IP $_DPORT --jump DNAT $_DNAT_DEST } sub_no_services() { # IF=eth0|ppp0... interface # IP=ip address of the local interface IF=$1 IP=$2 # Convenience defines: _DEST='--destination' _TCP="--protocol tcp" _UDP="--protocol udp" IPT=/sbin/iptables _DPORT='--destination-port' _REJECT='--jump REJECT' # Deny specific (local) services, since we still need # to allow privledged ports (<=1024) # 515 = lpr, 80 = http, 25 = smtp, 4321 = pmcd, 4330 = pmlogger ctrl # 21 = ftpd, 53 = named, 587 = sendmail-mta # 5335 = mDNSResponder # use 'REJECT' instead of 'DROP' so that you get a Connection Refused, # just as if the service did not exist. for SERVICE in 515 80 25 4321 4330 21 53 587 5335 ; do echo "$IPT --append $IF-inp $_DEST $IP $_TCP $_DPORT $SERVICE $_REJECT" $IPT --append $IF-inp $_DEST $IP $_TCP $_DPORT $SERVICE $_REJECT done # reject udp services # 67 = bootp (dhcpd), 53 = named, 5353 = mDNSResponder for SERVICE in 67 53 5353 ; do echo "$IPT --append $IF-inp $_DEST $IP $_UDP $_DPORT $SERVICE $_REJECT" $IPT --append $IF-inp $_DEST $IP $_UDP $_DPORT $SERVICE $_REJECT done unset SERVICE } sub_allow_service() { # IF=eth0|ppp0... interface # IP=ip address of the local interface # PORT=service port # to remove the rule for IF=$1 IP=$2 PORT=$3 # Convenience defines: _DEST='--destination' _TCP="--protocol tcp" _UDP="--protocol udp" IPT=/sbin/iptables _DPORT='--destination-port' _REJECT='--jump REJECT' # Deny specific (local) services, since we still need # to allow privledged ports (<=1024) # 515 = lpr, 80 = http, 25 = smtp, 4321 = pmcd, 4330 = pmlogger ctrl # 21 = ftpd, 53 = named, 587 = sendmail-mta # 5335 = mDNSResponder # use 'REJECT' instead of 'DROP' so that you get a Connection Refused, # just as if the service did not exist. echo "$IPT -D $IF-inp $_DEST $IP $_TCP $_DPORT $PORT $_REJECT" $IPT -D $IF-inp $_DEST $IP $_TCP $_DPORT $PORT $_REJECT # reject udp services # 67 = bootp (dhcpd), 53 = named, 5353 = mDNSResponder echo "$IPT -D $IF-inp $_DEST $IP $_UDP $_DPORT $PORT $_REJECT" $IPT -D $IF-inp $_DEST $IP $_UDP $_DPORT $PORT $_REJECT } install_external_tables() { # args: $IF $IP # IF=eth0|ppp0... interface # IP=ip address of the local interface IF=$1 IP=$2 echo $IF >/tmp/.iptables.external delete_external_tables $IF $IP # Convenience defines: _DEST='--destination' IPT=/sbin/iptables _DROP='--jump DROP' _ACCEPT='--jump ACCEPT' _INTF_IN="--in-interface $IF" for RULE in inp for out ; do # create or null==delete echo "$IPT --new-chain $IF-$RULE" $IPT --new-chain $IF-$RULE done ## NOTE: we don't need to include --interface $DEVICE because that ## check is done BEFORE jumping to the $IF-{inp,for,out} rules # Only allow packets targeted at that interface # irrelevant? see next entry echo "$IPT --append $IF-inp --destination ! $IP/32 $_DROP" $IPT --append $IF-inp --destination ! $IP/32 $_DROP # new iptables don't use filter/INPUT apparently when passing packets # through the router. put them into mangle/PREROUTING echo "$IPT -t mangle --append PREROUTING $_INTF_IN $_DEST ! $IP $_DROP" $IPT -t mangle --append PREROUTING $_INTF_IN $_DEST ! $IP $_DROP sub_no_services $IF $IP # # 2001.03.20 kjw - only allow specific hosts access to the 'net. see also dhcpd.conf # # default: reject access # echo "$IPT --append $IF-for $_DROP" # $IPT --append $IF-for $_DROP # Now that our personal chains are created, attach them to the real chains # deny obviously bad packets first. only packets for that if are allowed, # since it's a masquerading interface. echo "$IPT --insert INPUT 1 --in-interface $IF --jump $IF-inp" $IPT --insert INPUT 1 --in-interface $IF --jump $IF-inp # since we're masquerading, we should masq first before hitting internal # "internal, so just fwd it as is". echo "$IPT --insert FORWARD 1 --in-interface $IF --jump $IF-for" $IPT --insert FORWARD 1 --in-interface $IF --jump $IF-for # ... no output rules? ... #echo "$IPT --append OUTPUT --interface $IF --jump $IF-out" # $IPT --append OUTPUT --interface $IF --jump $IF-out } delete_external_tables() { IF=$1 IP=$2 # Convenience defines: IPT=/sbin/iptables _REJECT='--jump REJECT' _MASQ='--jump MASQUERADE' _ACCE='--jump ACCEPT' _TCP='--protocol tcp' _IF="--in-interface $IF" _INTF_IN="--in-interface $IF" _DEST='--destination' _DROP='--jump DROP' for RULE in INPUT FORWARD OUTPUT ; do case $RULE in INPUT) _DELETE="--delete $RULE" _INTF="--in-interface $IF" RUL=inp ;; FORWARD) _DELETE="--delete $RULE" _INTF="--in-interface $IF" RUL=for ;; OUTPUT) _DELETE="--delete $RULE" _INTF="--out-interface $IF" RUL=out ;; *) print "Unknown rule $RULE" return ;; esac # delete references to our chains echo "$IPT $_DELETE $_INTF --jump $IF-$RUL" $IPT $_DELETE $_INTF --jump $IF-$RUL # delete the chains themselves echo "$IPT -F $IF-$RUL" $IPT -F $IF-$RUL echo "$IPT -X $IF-$RUL" $IPT -X $IF-$RUL done echo "$IPT -t mangle --delete PREROUTING $_INTF_IN $_DEST ! $IP $_DROP" $IPT -t mangle --delete PREROUTING $_INTF_IN $_DEST ! $IP $_DROP } install_freewifi_tables() { # args: $IF $IP # IF=eth0|ppp0... interface # IP=ip address of the local interface IF=$1 IP=$2 NET=`ipcalc --network $IP 0xffffff00 | cut -f2 -d=` EXTERNAL_IF=`cat /tmp/.iptables.external` delete_internal_tables $IF $IP $EXTERNAL_IF # Convenience defines: IPT=/sbin/iptables _DEST='--destination' _DPORT='--destination-port' _TCP="--protocol tcp" _UDP="--protocol udp" _REJECT='--jump REJECT' _DROP='--jump DROP' _MASQ='--jump MASQUERADE' _ACCEPT='--jump ACCEPT' _OUT='--out-interface' for RULE in inp for out ; do # create or null==delete echo "$IPT --new-chain $IF-$RULE" $IPT --new-chain $IF-$RULE done ## NOTE: we don't need to include --interface $DEVICE because that ## check is done BEFORE jumping to the $IF-{inp,for,out} rules # deny all services except dns sub_no_services $IF $IP sub_allow_service $IF $IP 53 # dns sub_allow_service $IF $IP 67 # dhcp # let the subnet go out anywhere, if it has a legal src address echo "$IPT --insert $IF-for 1 --source $NET/24 $_OUT $EXTERNAL_IF $_ACCEPT" $IPT --insert $IF-for 1 --source $NET/24 $_OUT $EXTERNAL_IF $_ACCEPT echo "$IPT --insert $IF-for 1 --source ! $NET/24 $_REJECT" $IPT --insert $IF-for 1 --source ! $NET/24 $_REJECT # FEATURE: block destination smtp echo "$IPT --insert $IF-for 1 --source $NET/24 $_OUT $EXTERNAL_IF $_TCP --destination-port 25 $_REJECT" $IPT --insert $IF-for 1 --source $NET/24 $_OUT $EXTERNAL_IF $_TCP --destination-port 25 $_REJECT # FEATURE: masquerade # allow access echo "$IPT --insert POSTROUTING 1 --table nat --source $NET/24 $_MASQ" $IPT --insert POSTROUTING 1 --table nat --source $NET/24 $_MASQ # install these custom jump-to rules echo "$IPT --insert INPUT 1 --in-interface $IF --jump $IF-inp" $IPT --insert INPUT 1 --in-interface $IF --jump $IF-inp echo "$IPT --insert FORWARD 1 --in-interface $IF --jump $IF-for" $IPT --insert FORWARD 1 --in-interface $IF --jump $IF-for # ... no output rules? ... #echo "$IPT --append OUTPUT --interface $IF --jump $IF-out" # $IPT --append OUTPUT --interface $IF --jump $IF-out } install_internal_tables() { # args: $IF $IP # IF=eth0|ppp0... interface # IP=ip address of the local interface IF=$1 IP=$2 NET=`ipcalc --network $IP 0xffffff00 | cut -f2 -d=` delete_internal_tables $IF $IP # Convenience defines: IPT=/sbin/iptables _DEST='--destination' _DPORT='--destination-port' _TCP="--protocol tcp" _UDP="--protocol udp" _REJECT='--jump REJECT' _DROP='--jump DROP' _MASQ='--jump MASQUERADE' _ACCEPT='--jump ACCEPT' for RULE in inp for out ; do # create or null==delete echo "$IPT --new-chain $IF-$RULE" $IPT --new-chain $IF-$RULE done ## NOTE: we don't need to include --interface $DEVICE because that ## check is done BEFORE jumping to the $IF-{inp,for,out} rules # let the subnet go out anywhere, if it has a legal src address echo "$IPT --insert $IF-for 1 --source $NET/24 $_ACCEPT" $IPT --insert $IF-for 1 --source $NET/24 $_ACCEPT echo "$IPT --insert $IF-for 1 --source ! $NET/24 $_REJECT" $IPT --insert $IF-for 1 --source ! $NET/24 $_REJECT # FEATURE: masquerade # allow access echo "$IPT --insert POSTROUTING 1 --table nat --source $NET/24 $_MASQ" $IPT --insert POSTROUTING 1 --table nat --source $NET/24 $_MASQ # install these custom jump-to rules echo "$IPT --insert INPUT 1 --in-interface $IF --jump $IF-inp" $IPT --insert INPUT 1 --in-interface $IF --jump $IF-inp echo "$IPT --insert FORWARD 1 --in-interface $IF --jump $IF-for" $IPT --insert FORWARD 1 --in-interface $IF --jump $IF-for # ... no output rules? ... #echo "$IPT --append OUTPUT --interface $IF --jump $IF-out" # $IPT --append OUTPUT --interface $IF --jump $IF-out } delete_internal_tables() { # args: $IF $IP IF=$1 IP=$2 NET=`ipcalc --network $IP 0xffffff00 | cut -f2 -d=` IPT=/sbin/iptables # Convenience defines: _REJECT='--jump REJECT' _MASQ='--jump MASQUERADE' _ACCE='--jump ACCEPT' _TCP='--protocol tcp' _IF="--in-interface $IF" for RULE in INPUT FORWARD OUTPUT ; do case $RULE in INPUT) _DELETE="--delete $RULE" _INTF="--in-interface $IF" RUL=inp ;; FORWARD) _DELETE="--delete $RULE" _INTF="--in-interface $IF" RUL=for ;; OUTPUT) _DELETE="--delete $RULE" _INTF="--out-interface $IF" RUL=out ;; *) print "Unknown rule $RULE" return ;; esac # delete references to our chains echo "$IPT $_DELETE $_INTF --jump $IF-$RUL" $IPT $_DELETE $_INTF --jump $IF-$RUL # delete the chains themselves echo "$IPT -F $IF-$RUL" $IPT -F $IF-$RUL echo "$IPT -X $IF-$RUL" $IPT -X $IF-$RUL done # FEATURE: masquerade # give full access to the subnet echo "$IPT --table nat --delete POSTROUTING --source $NET/24 $_MASQ" $IPT --table nat --delete POSTROUTING --source $NET/24 $_MASQ } remove_captive_portal() { IF=$1 IP=$2 IPT='iptables' IN="--in-interface $IF" UDP_PORT="--protocol udp --destination-port " TCP_PORT="--protocol tcp --destination-port " MAC="-m mac --mac-source " $IPT -t nat -D wlan-accept $IPT -t nat -D wlan-private $IPT -t nat -D wlan $IPT -D wlan-accept $IPT -D wlan-private } install_captive_portal() { IF=$1 IP=$2 IPT='iptables' IN="--in-interface $IF" UDP_PORT="--protocol udp --destination-port " TCP_PORT="--protocol tcp --destination-port " MAC="-m mac --mac-source " # FEATURE: captive portal # table = nat # pre-define allowed mac addresses $IPT -t nat -N wlan-accept $IPT -t nat -N wlan-private $IPT -t nat -A wlan-private $MAC 00:02:2D:6C:01:E0 --jump ACCEPT # dell x200 $IPT -t nat -A wlan-private $MAC 00:11:24:97:a5:ab --jump ACCEPT # kjw-mac # create the rest of the routing rules $IPT -t nat -N wlan $IPT -t nat -I wlan 1 $UDP_PORT 67 --jump ACCEPT # allow dhcp $IPT -t nat -I wlan 2 $UDP_PORT 53 --jump ACCEPT # allow dns $IPT -t nat -I wlan 3 $TCP_PORT 53 --jump ACCEPT # allow dns $IPT -t nat -I wlan 4 --jump wlan-private # accept known mac addrs $IPT -t nat -I wlan 5 --jump wlan-accept # accept known mac addrs $IPT -t nat -I wlan 6 $TCP_PORT 80 --jump DNAT --to-destination 10.4.97.1 # default redirect web to local $IPT -t nat -A wlan --jump DROP # default REJECT # connect us in $IPT -t nat -I PREROUTING 1 $IN --jump wlan # table = filter (default) # these mac addresses have extra routing privledges $IPT -N wlan-private $IPT -A wlan-private $MAC 00:02:2D:6C:01:E0 --jump ACCEPT # dell x200 $IPT -A wlan-private $MAC 00:11:24:97:a5:ab --jump ACCEPT # kjw-mac $IPT -I FORWARD 1 $IN --jump wlan-private # restrict wlan to the outside world only $IPT -A FORWARD $IN --destination 10.10.220.1 --jump ACCEPT # $IPT -A FORWARD $IN $TCP_PORT 25 $_REJECT # auntie spam $IPT -N wlan-accept $IPT -A FORWARD $IN --jump wlan-accept $IPT -A FORWARD $IN $_REJECT # } ## end subroutines ## ######################################################################### exec >>/tmp/LOG.network_config exec 2>&1 echo "==================== start $0 $@" date LOGGER="logger -t network_config" ## parse and verify command-line MODE=$1 LOCATION=$2 IF=$3 IP=$4 $LOGGER "MODE=$MODE at LOCATION=$LOCATION on IF=$IF with IP=$IP" if [ "$MODE" != 'preup' -a "$MODE" != 'up' -a "$MODE" != 'down' ] then $LOGGER "ERROR: Mode [$MODE] is none of 'preup', 'up' or 'down'" exit 5 fi ## do the pre-up stuff if [ "$MODE" = 'preup' ] ; then case $LOCATION in BluetoothDialup) ;; # nothing to do here *) $LOGGER unknown location $LOCATION ;; esac exit 0 fi ## else do the up stuff if [ "$MODE" = 'up' ] ; then case $LOCATION in BluetoothDialup) NAMESERVER=`fgrep nameserver /etc/ppp/resolv.conf |head -1 |cut -f2- -d' '` DOMAIN=. make_resolv_conf ;; *) echo "ERROR: unknown location $LOCATION" $LOGGER "unknown $LOCATION" ;; esac exit 0 fi ## do the down stuff if [ "$MODE" = 'down' ] ; then case $LOCATION in BluetoothDialup) remove_resolv_conf ;; *) echo "ERROR: unknown location $LOCATION" $LOGGER "unknown $LOCATION" ;; esac exit 0 fi # NEVER GETS HERE echo "PROGRAMMER ERROR; should not get here #87721" exit 9