#!/bin/bash # arpshield 0.2 # Protects against ARP poisoning and cloaks your machine for all # local link devices but the router(s) and the DNS server(s). # Whitelisting DHCP servers also works if you use the dhcpcd program # to obtain DHCP leases. # This program is of no help if your setup is already poisoned. # Have a look at ArpON (http://arpon.sourceforge.net/manpage.html) if # you need more extensive protection. # # Needs 'ip', 'awk', 'sed', 'arptables', and 'arping' and expects # them on $PATH. Needs appropriate privileges (so use sudo). # Takes a network interface as an argument. The network interface # should be up and configured. If no argument is given, clear all # rules. Obviously you should do that before connecting to a new # network. # # Copyright 2010 Wicher Minnaard (wicher@gavagai.eu) # License: Creative Commons Attribution-Share Alike 3.0 # Do you use dhcpcd for aquiring DHCP leases? And is it running? dhcpcdLEASEFILE="/var/lib/dhcpcd-${1}.info" dhcpcdPIDFILE="/var/run/dhcpcd-${1}.pid" test -f ${dhcpcdLEASEFILE} && test -f ${dhcpcdPIDFILE} && source ${dhcpcdLEASEFILE} # In case you lack the luxury of dhcpcd, where is your resolv.conf? RESOLV="/etc/resolv.conf.dyn" # No user-servicable parts below this line. DEV="${1}" # I know, I know. But if your routing table contains 0.333.456.789 you have bigger problems ;-) IPREGEX="\([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}" # Register MACreg="" # If not run as root, bail [ "$(id -u)" != "0" ] && echo "You need root privileges to modify networking parameters. Exiting." 1>&2 && exit 2 getmac(){ # sets MAC register by IP. Sets to nil, if the MAC is not on the local link. getMAC=$(ip neigh show ${1} | awk '{print $5}') if [ -z "${getMAC}" ]; then arping -c1 -I ${DEV} ${1} > /dev/null 2>&1 getMAC=$(ip neigh show ${1} | awk '{print $5}') fi MACreg=${getMAC} } allow(){ # Whitelists traffic to and from particular IP+MAC pairings and # adds them to static ARP. IP=${1} MAC=${2} if [[ -n "${IP}" && -n "${MAC}" ]]; then arptables -A INPUT -s ${IP} --source-mac ${MAC} -j ACCEPT arptables -A OUTPUT -d ${IP} --destination-mac ${MAC} -j ACCEPT ip neigh replace ${IP} lladdr ${MAC} nud permanent dev ${DEV} fi } if [ -n "${DEV}" ]; then # whitelist the routers test -z ${GATEWAYS} && GATEWAYS=$(ip route show dev ${DEV}| sed -n "s:.* via \(${IPREGEX}\).*:\1:p") for GWIP in ${GATEWAYS}; do MACreg="" getmac ${GWIP} allow ${GWIP} ${MACreg} done # whitelist the DNS servers test -z ${DNSSERVERS} && DNSSERVERS=$(sed -n "s:^nameserver \(${IPREGEX}\):\1:p" ${RESOLV}) for DNS in ${DNSSERVERS}; do MACreg="" getmac ${DNS} allow ${DNS} ${MACreg} done # if using dhcpcd, we can whitelist the DHCP server too test -n ${DHCPSID} && getmac ${DHCPSID} && allow ${DHCPSID} ${MACreg} # set default policy to DROP arptables -P INPUT DROP arptables -P OUTPUT DROP # clear out non-hardcoded ARP cache entries ip neigh flush nud reachable ip neigh flush nud stale else # No argument given, so clean up. arptables -F arptables -P INPUT ACCEPT arptables -P OUTPUT ACCEPT ip neigh flush nud permanent fi