# frankenrouter.py by afx (c) 2018 deflax.net import subprocess import requests import json import datetime import os import sys import re clientiface = 'ens19' workscriptpath = '/root/fr-workscripts/' ### def writefile(filename, data): wr = open(filename, 'w') wr.write(data) wr.close() def bashexec(workfile, data): today = int(datetime.datetime.now().strftime("%s")) * 1000 script = """ #!/bin/bash # # {0} generated at {1} # IPT="/sbin/iptables" SYSCTL="/sbin/sysctl -w" # Internet Interface INET_IFACE="ens18" # Localhost Interface LO_IFACE="lo" LO_IP="127.0.0.1" {2}""".format(workfile, today, data) filename = os.path.join(workscriptpath, workfile + '.sh') #prevfile = os.path.join(workscriptpath, workfile + '-{}'.format(today) + '.bak') #subprocess.call('mv {0} {1}'.format(filename, prevfile), shell=True) subprocess.call('rm {0}'.format(filename), shell=True) writefile(filename, script) subprocess.call('chmod +x {}'.format(filename), shell=True) subprocess.call('{}'.format(filename), shell=True) def initfw(): data = """ echo "Loading kernel modules ..." /sbin/modprobe ip_tables /sbin/modprobe ip_conntrack # /sbin/modprobe iptable_filter # /sbin/modprobe iptable_mangle # /sbin/modprobe iptable_nat # /sbin/modprobe ipt_LOG # /sbin/modprobe ipt_limit # /sbin/modprobe ipt_MASQUERADE # /sbin/modprobe ipt_owner # /sbin/modprobe ipt_REJECT # /sbin/modprobe ipt_mark # /sbin/modprobe ipt_tcpmss # /sbin/modprobe multiport # /sbin/modprobe ipt_state # /sbin/modprobe ipt_unclean /sbin/modprobe ip_nat_ftp /sbin/modprobe ip_conntrack_ftp /sbin/modprobe ip_conntrack_irc if [ "$SYSCTL" = "" ] then echo "1" > /proc/sys/net/ipv4/ip_forward else $SYSCTL net.ipv4.ip_forward="1" fi if [ "$SYSCTL" = "" ] then echo "1" > /proc/sys/net/ipv4/tcp_syncookies else $SYSCTL net.ipv4.tcp_syncookies="1" fi if [ "$SYSCTL" = "" ] then echo "1" > /proc/sys/net/ipv4/conf/all/rp_filter else $SYSCTL net.ipv4.conf.all.rp_filter="1" fi if [ "$SYSCTL" = "" ] then echo "1" > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts else $SYSCTL net.ipv4.icmp_echo_ignore_broadcasts="1" fi if [ "$SYSCTL" = "" ] then echo "0" > /proc/sys/net/ipv4/conf/all/accept_source_route else $SYSCTL net.ipv4.conf.all.accept_source_route="0" fi if [ "$SYSCTL" = "" ] then echo "1" > /proc/sys/net/ipv4/conf/all/secure_redirects else $SYSCTL net.ipv4.conf.all.secure_redirects="1" fi #if [ "$SYSCTL" = "" ] #then # echo "1" > /proc/sys/net/ipv4/conf/all/log_martians #else # $SYSCTL net.ipv4.conf.all.log_martians="1" #fi echo "Flushing Tables ..." # Reset Default Policies $IPT -P INPUT ACCEPT $IPT -P FORWARD ACCEPT $IPT -P OUTPUT ACCEPT $IPT -t nat -P PREROUTING ACCEPT $IPT -t nat -P POSTROUTING ACCEPT $IPT -t nat -P OUTPUT ACCEPT $IPT -t mangle -P PREROUTING ACCEPT $IPT -t mangle -P OUTPUT ACCEPT $IPT -F $IPT -t nat -F $IPT -t mangle -F $IPT -X $IPT -t nat -X $IPT -t mangle -X if [ "$1" = "stop" ] then echo "Firewall completely flushed! Now running with no firewall." exit 0 fi $IPT -P INPUT DROP $IPT -P OUTPUT DROP $IPT -P FORWARD DROP $IPT -N bad_packets $IPT -N bad_tcp_packets $IPT -N icmp_packets $IPT -N udp_inbound $IPT -N udp_outbound $IPT -N tcp_inbound $IPT -N tcp_outbound #DEFAULT #$IPT -A bad_packets -p ALL -i $INET_IFACE -s $LOCAL_NET -j LOG --log-prefix "fp=bad_packets:2 a=DROP " #$IPT -A bad_packets -p ALL -i $INET_IFACE -s $LOCAL_NET -j DROP #$IPT -A bad_packets -p ALL -m state --state INVALID -j LOG --log-prefix "fp=bad_packets:1 a=DROP " $IPT -A bad_packets -p ALL -m state --state INVALID -j DROP $IPT -A bad_packets -p tcp -j bad_tcp_packets $IPT -A bad_packets -p ALL -j RETURN #$IPT -A bad_tcp_packets -p tcp -i $LOCAL_IFACE -j RETURN #$IPT -A bad_tcp_packets -p tcp ! --syn -m state --state NEW -j LOG --log-prefix "fp=bad_tcp_packets:1 a=DROP " $IPT -A bad_tcp_packets -p tcp ! --syn -m state --state NEW -j DROP #$IPT -A bad_tcp_packets -p tcp --tcp-flags ALL NONE -j LOG --log-prefix "fp=bad_tcp_packets:2 a=DROP " $IPT -A bad_tcp_packets -p tcp --tcp-flags ALL NONE -j DROP #$IPT -A bad_tcp_packets -p tcp --tcp-flags ALL ALL -j LOG --log-prefix "fp=bad_tcp_packets:3 a=DROP " $IPT -A bad_tcp_packets -p tcp --tcp-flags ALL ALL -j DROP #$IPT -A bad_tcp_packets -p tcp --tcp-flags ALL FIN,URG,PSH -j LOG --log-prefix "fp=bad_tcp_packets:4 a=DROP " $IPT -A bad_tcp_packets -p tcp --tcp-flags ALL FIN,URG,PSH -j DROP #$IPT -A bad_tcp_packets -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j LOG --log-prefix "fp=bad_tcp_packets:5 a=DROP " $IPT -A bad_tcp_packets -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP #$IPT -A bad_tcp_packets -p tcp --tcp-flags SYN,RST SYN,RST -j LOG --log-prefix "fp=bad_tcp_packets:6 a=DROP " $IPT -A bad_tcp_packets -p tcp --tcp-flags SYN,RST SYN,RST -j DROP #$IPT -A bad_tcp_packets -p tcp --tcp-flags SYN,FIN SYN,FIN -j LOG --log-prefix "fp=bad_tcp_packets:7 a=DROP " $IPT -A bad_tcp_packets -p tcp --tcp-flags SYN,FIN SYN,FIN -j DROP $IPT -A bad_tcp_packets -p tcp -j RETURN ### ICMP #$IPT -A icmp_packets --fragment -p ICMP -j LOG --log-prefix "fp=icmp_packets:1 a=DROP " #$IPT -A icmp_packets --fragment -p ICMP -j DROP #$IPT -A icmp_packets -p ICMP -s 0/0 --icmp-type 8 -j DROP #$IPT -A icmp_packets -p ICMP -s 0/0 --icmp-type 11 -j ACCEPT #$IPT -A icmp_packets -p ICMP -j RETURN $IPT -A icmp_packets -p ICMP -j ACCEPT #LOCAL $IPT -A udp_inbound -p UDP -s 0/0 --destination-port 137 -j DROP $IPT -A udp_inbound -p UDP -s 0/0 --destination-port 138 -j DROP $IPT -A udp_inbound -p UDP -s 0/0 --source-port 67 --destination-port 68 -j ACCEPT $IPT -A udp_inbound -p UDP -s 0/0 --destination-port 53 -j ACCEPT $IPT -A udp_inbound -p UDP -j RETURN $IPT -A tcp_inbound -p TCP -s 0/0 --destination-port 60022 -j ACCEPT $IPT -A tcp_inbound -p TCP -j RETURN $IPT -A udp_outbound -p UDP -s 0/0 -j ACCEPT $IPT -A tcp_outbound -p TCP -s 0/0 -j ACCEPT ############################################################################### echo "Process INPUT chain ..." $IPT -A INPUT -p ALL -i $LO_IFACE -j ACCEPT $IPT -A INPUT -p ALL -j bad_packets #INPUT index: 3 #$IPT -A INPUT -p ALL -i $INET_IFACE -m state --state ESTABLISHED,RELATED -j ACCEPT $IPT -A INPUT -p ALL -i $INET_IFACE -j ACCEPT $IPT -A INPUT -p TCP -i $INET_IFACE -j tcp_inbound $IPT -A INPUT -p UDP -i $INET_IFACE -j udp_inbound $IPT -A INPUT -p ICMP -i $INET_IFACE -j icmp_packets $IPT -A INPUT -m pkttype --pkt-type broadcast -j DROP #$IPT -A INPUT -j LOG --log-prefix "fp=INPUT:99 a=DROP " echo "Process FORWARD chain ..." $IPT -A FORWARD -p ALL -j bad_packets $IPT -A FORWARD -i $INET_IFACE -j ACCEPT #FORWARD index: 3 #$IPT -A FORWARD -j LOG --log-prefix "fp=FORWARD:99 a=DROP " echo "Process OUTPUT chain ..." #$IPT -A OUTPUT -m state -p icmp --state INVALID -j DROP $IPT -A OUTPUT -p ALL -s $LO_IP -j ACCEPT $IPT -A OUTPUT -p ALL -o $LO_IFACE -j ACCEPT #OUTPUT index: 3 $IPT -A OUTPUT -p ALL -o $INET_IFACE -j ACCEPT $IPT -A OUTPUT -j LOG --log-prefix "fp=OUTPUT:99 a=DROP " #$IPT -t nat -A POSTROUTING -o $INET_IFACE -j MASQUERADE """ return data def setvlans(clientiface, vlanmin=101, vlanmax=150): #vlans data = '' for vlanid in range(vlanmin, vlanmax + 1, 1): dhcpconf_template = """ #dhcpd.conf autogenerated by frankenrouter authoritative; default-lease-time 3600; max-lease-time 7200; ddns-update-style none; option subnet-mask 255.255.255.0; option domain-name-servers 87.120.110.2, 8.8.8.8; #vlan {0} host vlan{0}-vm {{ hardware ethernet 8A:32:CD:E4:EE:11; fixed-address 10.0.{0}.10; }} subnet 10.0.{0}.0 netmask 255.255.255.0 {{ option routers 10.0.{0}.1; range 10.0.{0}.11 10.0.{0}.99; }} """.format(vlanid) writefile('/root/fr-vlanconf/v{0}.dhconf'.format(vlanid), dhcpconf_template) data += """ ### VLAN {0} echo "setting up vlan: {0}" kill -9 `cat /root/fr-vlanconf/v{0}.dhpid` rm /root/fr-vlanconf/v{0}.dhpid ip link del {1}.{0} ip link add link {1} name {1}.{0} type vlan id {0} ip link set dev {1}.{0} up ip addr add 10.0.{0}.1/24 dev {1}.{0} #$IPT -I INPUT 3 -p ALL -i {1}.{0} -d 10.0.{0}.255 -j ACCEPT $IPT -I INPUT 3 -p ALL -i {1}.{0} -s 10.0.{0}.0/24 -j ACCEPT $IPT -I FORWARD 3 -p ALL -i {1}.{0} -s 10.0.{0}.10 -j ACCEPT #$IPT -I FORWARD 3 -p ALL -i {1}.{0} -o $INET_IFACE -s 10.0.{0}.10 -j ACCEPT ##$IPT -I FORWARD 3 -p ALL -i $INET_IFACE -o {1}.{0} -d 10.0.{0}.10 -m state --state NEW -j ACCEPT $IPT -I OUTPUT 3 -p ALL -o {1}.{0} -j ACCEPT touch /root/fr-vlanconf/v{0}.dhpid touch /root/fr-vlanconf/v{0}.dhlease dhcpd -4 -cf /root/fr-vlanconf/v{0}.dhconf -lf /root/fr-vlanconf/v{0}.dhlease -pf /root/fr-vlanconf/v{0}.dhpid {1}.{0} """.format(vlanid, clientiface) return data def allipsetup(iplist): rr = open(iplist, 'r').read() cache = json.loads(rr) conffile = open('/root/frankenrouter/config.sh', 'r') for line in conffile: if re.search('TRANSPORT_MASK', line): ip_mask = line.split('=', 1)[1].rstrip().replace('"', '') conffile.close() for ip, vlan in cache.items(): bashexec('ipadd-{}-{}'.format(ip, vlan), assignip(ip, ip_mask, vlan)) def assignip(ip, ip_mask, vlan): data = """ ip link add vtap{1} link $INET_IFACE type macvlan ip addr add {0}/{2} dev vtap{1} ip link set dev vtap{1} up $IPT -t nat -A PREROUTING -d {0} -j DNAT --to-destination 10.0.{1}.10 $IPT -t nat -A POSTROUTING -s 10.0.{1}.10 -j SNAT --to-source {0} """.format(ip, vlan, ip_mask) return data def removeip(ip, vlan): data = """ ip link set dev vtap{1} down ip link delete vtap{1} $IPT -t nat -D PREROUTING -d {0} -j DNAT --to-destination 10.0.{1}.10 $IPT -t nat -D POSTROUTING -s 10.0.{1}.10 -j SNAT --to-source {0} """.format(ip, vlan) return data if __name__ == "__main__": helpdata = """ python3 frankenrouter.py init --- setup the default firewall, read the contents of /root/pubip.cache and setup all assigments. Useful on startup python3 ipadd VLAN IP --- add IP to VLAN python3 ipdel VLAN IP --- del IP from VLAN """ try: if sys.argv[1] == 'init': bashexec('fwsetup', initfw()) bashexec('vlsetup', setvlans(clientiface)) if sys.argv[1] == 'allipadd': bashexec('allipsetup', allipsetup('/root/pubip.cache')) if sys.argv[1] == 'ipadd': bashexec('ipadd-{}-{}'.format(sys.argv[2], sys.argv[3]), assignip(sys.argv[2], sys.argv[3])) if sys.argv[1] == 'ipdel': bashexec('ipdel-{}-{}'.format(sys.argv[2], sys.argv[3]), removeip(sys.argv[2], sys.argv[3])) except Exception as e: print(str(e)) print(helpdata)