diff --git a/bin/pfatt-5268AC.rc b/bin/pfatt-5268AC.rc new file mode 100644 index 0000000..258deb7 --- /dev/null +++ b/bin/pfatt-5268AC.rc @@ -0,0 +1,50 @@ +#!/bin/sh + +script_path="/cf/conf/pfatt/bin/pfatt-5268AC.sh" + +name=`/usr/bin/basename "${script_path}"` + +rc_start() { + ### Lock out other start signals until we are done + /usr/bin/touch /var/run/${name}.lck + + ${script_path} & + pid=$! + + if [ $pid ]; then + echo $pid > /var/run/${name}.pid + /usr/bin/logger -p daemon.info -i -t pfatt-5268AC "successfully started ${name}" + else + /usr/bin/logger -p daemon.error -i -t pfatt-5268AC "error starting ${name}" + fi + + ### Remove the lock + if [ -f /var/run/${name}.lck ]; then + /bin/sleep 2 + /bin/rm /var/run/${name}.lck + fi +} + +rc_stop() { + if [ -f /var/run/${name}.pid ]; then + kill -9 `cat /var/run/${name}.pid` + /bin/rm /var/run/${name}.pid + fi +} + +case $1 in + start) + if [ ! -f /var/run/${name}.lck ]; then + rc_start + fi + ;; + stop) + rc_stop + ;; + restart) + if [ ! -f /var/run/${name}.lck ]; then + rc_stop + rc_start + fi + ;; +esac diff --git a/bin/pfatt-5268AC.sh b/bin/pfatt-5268AC.sh index e886923..a426f0d 100644 --- a/bin/pfatt-5268AC.sh +++ b/bin/pfatt-5268AC.sh @@ -1,31 +1,35 @@ -#!/bin/sh +#!/usr/bin/env sh +# +# CONFIG +# ====== +# +# PING_HOST - IP where ping should check for connectivity +# +# SLEEP - How often to check connectivity in seconds +# + PING_HOST=8.8.8.8 SLEEP=5 -LOG=/var/log/pfatt.log -getTimestamp(){ - echo `date "+%Y-%m-%d %H:%M:%S :: [pfatt-5268AC.sh] ::"` -} +############################################################################### -{ - RG_CONNECTED="/usr/sbin/ngctl show laneapfilter:eapout" +RG_CONNECTED="/usr/sbin/ngctl show laneapfilter:eapout" - echo "$(getTimestamp) Starting 5268AC ping monitor ..." - while - if /sbin/ping -t2 -q -c1 $PING_HOST > /dev/null ; then - if $RG_CONNECTED >/dev/null 2>&1 ; then - echo "$(getTimestamp) Connection to $PING_HOST is up, but EAP is being bridged!" - echo -n "$(getTimestamp) Disconnecting netgraph node ... " - /usr/sbin/ngctl rmhook laneapfilter: eapout && echo "OK!" || echo "ERROR!" - fi - else - if ! $RG_CONNECTED >/dev/null 2>&1 ; then - echo "$(getTimestamp) Connection to $PING_HOST is down, but EAP is not being bridged!" - echo -n "$(getTimestamp) Connecting netgraph node ... " - /usr/sbin/ngctl connect waneapfilter: laneapfilter: eapout eapout && echo "OK!" || echo "ERROR!" - fi +/usr/bin/logger -sit "pfatt-5268AC" "starting 5268AC ping monitor..." +while +if /sbin/ping -t2 -q -c1 $PING_HOST > /dev/null ; then + if $RG_CONNECTED >/dev/null 2>&1 ; then + /usr/bin/logger -sit "pfatt-5268AC" "connection to $PING_HOST is up, but EAP is being bridged!" + /usr/bin/logger -sit "pfatt-5268AC" "removing laneapfilter: eapout netgraph hook..." + /usr/sbin/ngctl rmhook laneapfilter: eapout fi - sleep $SLEEP - do :; done - echo "$(getTimestamp) Stopping 5268AC ping monitor ..." -} >> $LOG \ No newline at end of file +else + if ! $RG_CONNECTED >/dev/null 2>&1 ; then + /usr/bin/logger -sit "pfatt-5268AC" "connection to $PING_HOST is down, but EAP is not being bridged!" + /usr/bin/logger -sit "pfatt-5268AC" "connecting waneapfilter: -> laneapfilter: netgraph nodes..." + /usr/sbin/ngctl connect waneapfilter: laneapfilter: eapout eapout + fi +fi +sleep $SLEEP +do :; done +/usr/bin/logger -sit "pfatt-5268AC" "stopping 5268AC ping monitor ..." diff --git a/bin/pfatt.sh b/bin/pfatt.sh index b381e74..9f593c3 100755 --- a/bin/pfatt.sh +++ b/bin/pfatt.sh @@ -1,99 +1,232 @@ -#!/bin/sh -set -e +#!/usr/bin/env sh +# +# CONFIG +# ====== +# +# ONT_IF Interface connected to the ONT +# +# RG_ETHER_ADDR MAC address of your assigned Residential Gateway +# +# EAP_MODE EAP authentication mode: supplicant or bridge +# +# supplicant Use wpa_supplicant to authorize your connection. +# Requires valid certs in /conf/pfatt/wpa. No +# Residential Gateway connection required. +# +# bridge Bridge EAPoL traffic from your Residential Gateway to +# authorize your connection. Residential Gateway +# connection required. +# +# EAP_SUPPLICANT_IDENTITY Required only with supplicant mode. MAC address associated +# with your cert used as your EAP-TLS identity. If you extracted +# the cert from your stock issue residential gateway, this is the +# same as $RG_ETHER_ADDR. +# +# EAP_BRIDGE_IF Required only with bridge mode. Interface that is connected +# to your Residential Gateway. +# +# EAP_BRIDGE_5268AC Required only with bridge mode. Enable workaround for 5268AC. +# Enable if you have the 5268AC. See https://github.com/aus/pfatt/issues/5 +# for details. 0=OFF 1=ON +# -ONT_IF='em0' -RG_IF='em1' -RG_ETHER_ADDR='xx:xx:xx:xx:xx:xx' -LOG=/var/log/pfatt.log +# Required Config +# =============== +ONT_IF="igb0" +RG_ETHER_ADDR="00:00:00:00:00:00" +EAP_MODE="bridge" -# Calculate pfsense version so we can manage some variations. -VERSION_MAJOR=`sed -nre 's/([0-9])+\.([0-9])+\.([0-9])+.*/\1/p' /etc/version` -VERSION_MINOR=`sed -nre 's/([0-9])+\.([0-9])+\.([0-9])+.*/\2/p' /etc/version` -VERSION_PATCH=`sed -nre 's/([0-9])+\.([0-9])+\.([0-9])+.*/\3/p' /etc/version` +# Supplicant Config +# ================= +EAP_SUPPLICANT_IDENTITY="00:00:00:00:00:00" -getTimestamp(){ - echo `date "+%Y-%m-%d %H:%M:%S :: [pfatt.sh] ::"` -} +# Bridge Config +# ============= +EAP_BRIDGE_IF="igb1" +EAP_BRIDGE_5268AC=0 -{ - echo "$(getTimestamp) pfSense + AT&T U-verse Residential Gateway for true bridge mode" - echo "$(getTimestamp) Configuration: " - echo "$(getTimestamp) ONT_IF: $ONT_IF" - echo "$(getTimestamp) RG_IF: $RG_IF" - echo "$(getTimestamp) RG_ETHER_ADDR: $RG_ETHER_ADDR" +##### DO NOT EDIT BELOW ################################################################################# - if ( [ ${VERSION_MAJOR} -ge '2' ] && [ ${VERSION_MINOR} -ge '4' ] && [ ${VERSION_PATCH} -lt '5' ] ); then - echo -n "$(getTimestamp) loading netgraph kernel modules... " - /sbin/kldload -nq ng_etf - echo "OK!" +/usr/bin/logger -st "pfatt" "starting pfatt..." +/usr/bin/logger -st "pfatt" "configuration:" +/usr/bin/logger -st "pfatt" " ONT_IF = $ONT_IF" +/usr/bin/logger -st "pfatt" " RG_ETHER_ADDR = $RG_ETHER_ADDR" +/usr/bin/logger -st "pfatt" " EAP_MODE = $EAP_MODE" +/usr/bin/logger -st "pfatt" " EAP_SUPPLICANT_IDENTITY = $EAP_SUPPLICANT_IDENTITY" +/usr/bin/logger -st "pfatt" " EAP_BRIDGE_IF = $EAP_BRIDGE_IF" +/usr/bin/logger -st "pfatt" " EAP_BRIDGE_5268AC = $EAP_BRIDGE_5268AC" + +/usr/bin/logger -st "pfatt" "resetting netgraph..." +/usr/sbin/ngctl shutdown waneapfilter: >/dev/null 2>&1 +/usr/sbin/ngctl shutdown laneapfilter: >/dev/null 2>&1 +/usr/sbin/ngctl shutdown $ONT_IF: >/dev/null 2>&1 +/usr/sbin/ngctl shutdown $EAP_BRIDGE_IF: >/dev/null 2>&1 +/usr/sbin/ngctl shutdown o2m: >/dev/null 2>&1 +/usr/sbin/ngctl shutdown vlan0: >/dev/null 2>&1 +/usr/sbin/ngctl shutdown ngeth0: >/dev/null 2>&1 + +if [ "$EAP_MODE" = "bridge" ] ; then + /usr/bin/logger -st "pfatt" "configuring EAP environment for $EAP_MODE mode..." + /usr/bin/logger -st "pfatt" "cabling should look like this:" + /usr/bin/logger -st "pfatt" " ONT---[] [$ONT_IF]$HOST[$EAP_BRIDGE_IF] []---[] [ONT_PORT]ResidentialGateway" + /usr/bin/logger -st "pfatt" "loading netgraph kernel modules..." + /sbin/kldload -nq /conf/pfatt/bin/ng_etf.ko + /usr/bin/logger -st "pfatt" "attaching interfaces to ng_ether..." + /usr/local/bin/php -r "pfSense_ngctl_attach('.', '$ONT_IF');" + /usr/local/bin/php -r "pfSense_ngctl_attach('.', '$EAP_BRIDGE_IF');" + + /usr/bin/logger -st "pfatt" "building netgraph nodes..." + + /usr/bin/logger -st "pfatt" "creating ng_one2many..." + /usr/sbin/ngctl mkpeer $ONT_IF: one2many lower one + /usr/sbin/ngctl name $ONT_IF:lower o2m + + /usr/bin/logger -st "pfatt" "creating vlan node and interface..." + /usr/sbin/ngctl mkpeer o2m: vlan many0 downstream + /usr/sbin/ngctl name o2m:many0 vlan0 + /usr/sbin/ngctl mkpeer vlan0: eiface vlan0 ether + /usr/sbin/ngctl msg vlan0: 'addfilter { vlan=0 hook="vlan0" }' + /usr/sbin/ngctl msg ngeth0: set $RG_ETHER_ADDR + + /usr/bin/logger -st "pfatt" "defining etf for $ONT_IF (ONT)..." + /usr/sbin/ngctl mkpeer o2m: etf many1 downstream + /usr/sbin/ngctl name o2m:many1 waneapfilter + /usr/sbin/ngctl connect waneapfilter: $ONT_IF: nomatch upper + + /usr/bin/logger -st "pfatt" "defining etf for $EAP_BRIDGE_IF (RG)... " + /usr/sbin/ngctl mkpeer $EAP_BRIDGE_IF: etf lower downstream + /usr/sbin/ngctl name $EAP_BRIDGE_IF:lower laneapfilter + /usr/sbin/ngctl connect laneapfilter: $EAP_BRIDGE_IF: nomatch upper + + /usr/bin/logger -st "pfatt" "bridging etf for $ONT_IF <-> $EAP_BRIDGE_IF... " + /usr/sbin/ngctl connect waneapfilter: laneapfilter: eapout eapout + + /usr/bin/logger -st "pfatt" "defining filters for EAP traffic... " + /usr/sbin/ngctl msg waneapfilter: 'setfilter { matchhook="eapout" ethertype=0x888e }' + /usr/sbin/ngctl msg laneapfilter: 'setfilter { matchhook="eapout" ethertype=0x888e }' + + /usr/bin/logger -st "pfatt" "enabling one2many links... " + /usr/sbin/ngctl msg o2m: setconfig "{ xmitAlg=2 failAlg=1 enabledLinks=[ 1 1 ] }" + + /usr/bin/logger -st "pfatt" "removing waneapfilter:nomatch hook... " + /usr/sbin/ngctl rmhook waneapfilter: nomatch + + /usr/bin/logger -st "pfatt" "enabling interfaces..." + /sbin/ifconfig $EAP_BRIDGE_IF up + /sbin/ifconfig $ONT_IF up + + /usr/bin/logger -st "pfatt" "enabling promiscuous mode..." + /sbin/ifconfig $EAP_BRIDGE_IF promisc + /sbin/ifconfig $ONT_IF promisc + + logger -st "pfatt" "waiting for EAP to complete authorization (unimplemented!)..." + # TODO: detect, wait for EAP + # TODO: force DHCP if needed + + if [ "$EAP_BRIDGE_5268AC" = "1" ] ; then + # install proper rc script + /bin/cp /conf/pfatt/bin/pfatt-5268AC.rc /usr/local/etc/rc.d/pfatt-5268AC.sh + # kill any existing pfatt-5268AC process + PID=$(pgrep -f "pfatt-5268AC") + if [ ${PID} > 0 ]; then + /usr/bin/logger -st "pfatt" "terminating existing pfatt-5268AC on PID ${PID}..." + RES=$(kill ${PID}) + /usr/local/etc/rc.d/pfatt-5268AC.sh stop fi + /usr/bin/logger -st "pfatt" "enabling 5268AC workaround..." + /usr/local/etc/rc.d/pfatt-5268AC.sh start + fi + /usr/bin/logger -st "pfatt" "ngeth0 should now be available to configure as your WAN..." + /usr/bin/logger -st "pfatt" "done!" - echo -n "$(getTimestamp) attaching interfaces to ng_ether... " - /usr/local/bin/php -r "pfSense_ngctl_attach('.', '$ONT_IF');" - /usr/local/bin/php -r "pfSense_ngctl_attach('.', '$RG_IF');" - echo "OK!" +elif [ "$EAP_MODE" = "supplicant" ] ; then + /usr/bin/logger -st "pfatt" "configuring EAP environment for $EAP_MODE mode..." + /usr/bin/logger -st "pfatt" "cabling should look like this:" + /usr/bin/logger -st "pfatt" " ONT---[] [$ONT_IF]$HOST" + /usr/bin/logger -st "pfatt" "creating vlan node and ngeth0 interface..." + /usr/sbin/ngctl mkpeer $ONT_IF: vlan lower downstream + /usr/sbin/ngctl name $ONT_IF:lower vlan0 + /usr/sbin/ngctl mkpeer vlan0: eiface vlan0 ether + /usr/sbin/ngctl msg vlan0: 'addfilter { vlan=0 hook="vlan0" }' + /usr/sbin/ngctl msg ngeth0: set $RG_ETHER_ADDR - echo "$(getTimestamp) building netgraph nodes..." + /usr/bin/logger -st "pfatt" "enabling promisc for $ONT_IF..." + /sbin/ifconfig $ONT_IF up + /sbin/ifconfig $ONT_IF promisc - echo -n "$(getTimestamp) creating ng_one2many... " - /usr/sbin/ngctl mkpeer $ONT_IF: one2many lower one - /usr/sbin/ngctl name $ONT_IF:lower o2m - echo "OK!" + /usr/bin/logger -st "pfatt" "starting wpa_supplicant..." - echo -n "$(getTimestamp) creating vlan node and interface... " - /usr/sbin/ngctl mkpeer o2m: vlan many0 downstream - /usr/sbin/ngctl name o2m:many0 vlan0 - /usr/sbin/ngctl mkpeer vlan0: eiface vlan0 ether + WPA_PARAMS="\ + set eapol_version 2,\ + set fast_reauth 1,\ + ap_scan 0,\ + add_network,\ + set_network 0 ca_cert \\\"/conf/pfatt/wpa/ca.pem\\\",\ + set_network 0 client_cert \\\"/conf/pfatt/wpa/client.pem\\\",\ + set_network 0 eap TLS,\ + set_network 0 eapol_flags 0,\ + set_network 0 identity \\\"$EAP_SUPPLICANT_IDENTITY\\\",\ + set_network 0 key_mgmt IEEE8021X,\ + set_network 0 phase1 \\\"allow_canned_success=1\\\",\ + set_network 0 private_key \\\"/conf/pfatt/wpa/private.pem\\\",\ + enable_network 0\ + " - /usr/sbin/ngctl msg vlan0: 'addfilter { vlan=0 hook="vlan0" }' - /usr/sbin/ngctl msg ngeth0: set $RG_ETHER_ADDR - echo "OK!" + WPA_DAEMON_CMD="/usr/sbin/wpa_supplicant -Dwired -ingeth0 -B -C /var/run/wpa_supplicant" - echo -n "$(getTimestamp) defining etf for $ONT_IF (ONT)... " - /usr/sbin/ngctl mkpeer o2m: etf many1 downstream - /usr/sbin/ngctl name o2m:many1 waneapfilter - /usr/sbin/ngctl connect waneapfilter: $ONT_IF: nomatch upper - echo "OK!" + # kill any existing wpa_supplicant process + PID=$(pgrep -f "wpa_supplicant.*ngeth0") + if [ ${PID} > 0 ]; + then + /usr/bin/logger -st "pfatt" "terminating existing wpa_supplicant on PID ${PID}..." + RES=$(kill ${PID}) + fi - echo -n "$(getTimestamp) defining etf for $RG_IF (RG)... " - /usr/sbin/ngctl mkpeer $RG_IF: etf lower downstream - /usr/sbin/ngctl name $RG_IF:lower laneapfilter - /usr/sbin/ngctl connect laneapfilter: $RG_IF: nomatch upper - echo "OK!" + # start wpa_supplicant daemon + RES=$(${WPA_DAEMON_CMD}) + PID=$(pgrep -f "wpa_supplicant.*ngeth0") + /usr/bin/logger -st "pfatt" "wpa_supplicant running on PID ${PID}..." - echo -n "$(getTimestamp) bridging etf for $ONT_IF <-> $RG_IF... " - /usr/sbin/ngctl connect waneapfilter: laneapfilter: eapout eapout - echo "OK!" + # Set WPA configuration parameters. + /usr/bin/logger -st "pfatt" "setting wpa_supplicant network configuration..." + IFS="," + for STR in ${WPA_PARAMS}; + do + STR="$(echo -e "${STR}" | sed -e 's/^[[:space:]]*//')" + RES=$(eval wpa_cli ${STR}) + done - echo -n "$(getTimestamp) defining filters for EAP traffic... " - /usr/sbin/ngctl msg waneapfilter: 'setfilter { matchhook="eapout" ethertype=0x888e }' - /usr/sbin/ngctl msg laneapfilter: 'setfilter { matchhook="eapout" ethertype=0x888e }' - echo "OK!" + # wait until wpa_cli has authenticated. + WPA_STATUS_CMD="wpa_cli status | grep 'suppPortStatus' | cut -d= -f2" + IP_STATUS_CMD="ifconfig ngeth0 | grep 'inet\ ' | cut -d' ' -f2" - echo -n "$(getTimestamp) enabling one2many links... " - /usr/sbin/ngctl msg o2m: setconfig "{ xmitAlg=2 failAlg=1 enabledLinks=[ 1 1 ] }" - echo "OK!" + /usr/bin/logger -st "pfatt" "waiting EAP for authorization..." - echo -n "$(getTimestamp) removing waneapfilter:nomatch hook... " - /usr/sbin/ngctl rmhook waneapfilter: nomatch - echo "OK!" + # TODO: blocking for bootup + while true; + do + WPA_STATUS=$(eval ${WPA_STATUS_CMD}) + if [ X${WPA_STATUS} = X"Authorized" ]; + then + /usr/bin/logger -st "pfatt" "EAP authorization completed..." - echo -n "$(getTimestamp) enabling $RG_IF interface... " - /sbin/ifconfig $RG_IF up - echo "OK!" + IP_STATUS=$(eval ${IP_STATUS_CMD}) - echo -n "$(getTimestamp) enabling $ONT_IF interface... " - /sbin/ifconfig $ONT_IF up - echo "OK!" - - echo -n "$(getTimestamp) enabling promiscuous mode on $RG_IF... " - /sbin/ifconfig $RG_IF promisc - echo "OK!" - - echo -n "$(getTimestamp) enabling promiscuous mode on $ONT_IF... " - /sbin/ifconfig $ONT_IF promisc - echo "OK!" - - echo "$(getTimestamp) ngeth0 should now be available to configure as your pfSense WAN" - echo "$(getTimestamp) done!" -} >> $LOG + if [ -z ${IP_STATUS} ] || [ ${IP_STATUS} = "0.0.0.0" ]; + then + /usr/bin/logger -st "pfatt" "no IP address assigned, force restarting DHCP..." + RES=$(eval /etc/rc.d/dhclient forcerestart ngeth0) + IP_STATUS=$(eval ${IP_STATUS_CMD}) + fi + /usr/bin/logger -st "pfatt" "IP address is ${IP_STATUS}..." + break + else + sleep 1 + fi + done + /usr/bin/logger -st "pfatt" "ngeth0 should now be available to configure as your WAN..." + /usr/bin/logger -st "pfatt" "done!" +else + /usr/bin/logger -st "pfatt" "error: unknown EAP_MODE. '$EAP_MODE' is not valid. exiting..." + exit 1 +fi \ No newline at end of file