Last active
August 29, 2015 14:05
-
-
Save mhahl/07ed57e56cfb801af93f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/ruby | |
###################################################### | |
# | |
# Author: Mark Hahl | |
# Email: mark@deviateit.net | |
# Version: 0.0.0 | |
# | |
# Firewall configuration script for gateway server, | |
# managing traffic and other rules. | |
# | |
##################################################### | |
require 'yaml' | |
puts "#" | |
puts "# Firewall Script Generated at #{Time.now}" | |
puts "# Do not edit this script directly." | |
puts "#" | |
# Interfaces the server will use | |
# there could be more than this | |
# when we get the new device | |
# | |
INT = "eth1" | |
EXT = "eth0" | |
IPT = "iptables" | |
ARP = "arptables" | |
SAR = "arp" | |
GW = "10.0.0.1" | |
# Quota limits (In Bytes). | |
# - Q_ON: Quota for onpeak hours | |
# - Q_OFF: Quota for off peak hours. | |
# | |
Q_ON = 125000000000 | |
Q_OFF = 125000000000 | |
# Time frame for quota counting depending | |
# on time frame. | |
# - TIME_START: Start of onpeak hours | |
# begining of off peak hours. | |
# - TIME_STOP: Stop of onpeak hours | |
# begining of off peak hours | |
# | |
TIME_START = "07:00" | |
TIME_STOP = "19:00" | |
# Internode UNMERTERED content list of IP addresses. | |
# this should be the file AS IS from the URL: | |
# | |
# https://customer-webtools-api.internode.on.net/unmetered_ip_address_list.txt | |
# | |
UNMETERED_CONTENT = File.read("conf/unmetered_ip_address_list.txt") | |
# Users and there IP Addresses and | |
# mac addresses associated with them | |
# associated with the user.The output from | |
# the file should look like the hashmap below: | |
# | |
# USERS = { | |
# :MARK => { | |
# "10.0.0.20" => "00:b5:6d:00:f9:50", | |
# "10.0.0.21" => "00:b5:6d:00:f9:51", | |
# "10.0.0.22" => "00:b5:6d:00:f9:52", | |
# }, | |
# :JACK => { | |
# "10.0.0.10" => "74:D0:2B:CB:80:CB" | |
# } | |
# } | |
# | |
USERS = YAML::load(File.read("conf/clients.yaml")) | |
# Flush all the rules. | |
# | |
puts "#{IPT} -F" | |
# Delete tables for QUOTAS if they already exist. | |
# this stops the script from complaining. | |
# | |
USERS.each do |user, ips| | |
puts "#{IPT} -X #{user}_QUOTA" | |
end | |
# Default policies for | |
# the firewall is to drop everything | |
# unless there is a rule allowing. | |
# | |
puts "#{IPT} -P INPUT DROP" | |
puts "#{IPT} -P FORWARD DROP" | |
puts "#{IPT} -P OUTPUT ACCEPT" | |
# Enable NAT or something | |
# similar. | |
# | |
puts "#{IPT} -t nat -A POSTROUTING -o #{EXT} -j MASQUERADE" | |
# Set all UDP trafic to minimal-delay. | |
# | |
puts "#{IPT} -t mangle -A PREROUTING -p udp -j TOS --set-tos 0x04" | |
# Drop invalid packets straigt away. | |
# | |
puts "#{IPT} -A INPUT -m state --state INVALID -j DROP" | |
puts "#{IPT} -A FORWARD -m state --state INVALID -j DROP" | |
puts "#{IPT} -A OUTPUT -m state --state INVALID -j DROP" | |
# Accept ICMP and all traffic from loopback. | |
# | |
puts "#{IPT} -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT" | |
puts "#{IPT} -A INPUT -i lo -j ACCEPT" | |
puts "#{IPT} -A INPUT -p icmp -j ACCEPT" | |
puts "#{IPT} -A INPUT -i eth1 -j ACCEPT" | |
puts "#{IPT} -A OUTPUT -o eth1 -j ACCEPT" | |
# Drop bogus TCP packets | |
# | |
puts "#{IPT} -A INPUT -p tcp -m tcp --tcp-flags SYN,FIN SYN,FIN -j DROP" | |
puts "#{IPT} -A INPUT -p tcp -m tcp --tcp-flags SYN,RST SYN,RST -j DROP" | |
# Open ports for services. | |
# - 22: SSH Server | |
# - 67: DHCP | |
# - 68: DHCP | |
# - 53: DNS | |
# | |
puts "#{IPT} -A INPUT -p tcp --dport 22 -j ACCEPT" | |
puts "#{IPT} -A INPUT -p tcp --dport 67 -j ACCEPT" | |
puts "#{IPT} -A INPUT -p tcp --dport 68 -j ACCEPT" | |
puts "#{IPT} -A INPUT -p tcp --dport 53 -j ACCEPT" | |
puts "#{IPT} -A INPUT -j DROP" | |
# Forward and accept all packets to the Internode Unmetered IPS | |
# These will not get forwared to the quota chain and wont be | |
# counted. | |
# | |
UNMETERED_CONTENT.split("\n\n")[0].each_line do |ip| | |
puts "#{IPT} -A FORWARD -s #{ip.strip()} -j ACCEPT" | |
puts "#{IPT} -A FORWARD -d #{ip.strip()} -j ACCEPT" | |
end | |
# Create the monitoring table for each user | |
# This will count and block the user when the quota reaches the limit. | |
# | |
USERS.each do |user, ips| | |
puts "#{IPT} -N #{user}_QUOTA" | |
puts "#{IPT} -A #{user}_QUOTA -m quota --quota #{Q_ON} -m time --timestart #{TIME_STOP} --timestop #{TIME_START} -j ACCEPT" | |
puts "#{IPT} -A #{user}_QUOTA -m quota --quota #{Q_OFF} -m time --timestart #{TIME_START} --timestop #{TIME_STOP} -j ACCEPT" | |
end | |
# When a packet is received, forwared it on to the | |
# quota chain. | |
# | |
USERS.each do |user, hosts| | |
hosts.each do |ip, mac| | |
puts "#{IPT} -A FORWARD -d #{ip} -j #{user}_QUOTA" | |
puts "#{IPT} -A FORWARD -s #{ip} -j #{user}_QUOTA" | |
end | |
end | |
# Drop everything that doesn't match the above rules. | |
# | |
puts "#{IPT} -A FORWARD -j REJECT --reject-with icmp-admin-prohibited" | |
# Flush the arptables rules | |
# set default policy to drop everything. | |
# | |
puts "#{ARP} -F" | |
puts "#{ARP} -P IN DROP" | |
puts "#{ARP} -P OUT ACCEPT" | |
puts "#{ARP} -P FORWARD ACCEPT" | |
# Set up arp tables to do the policy enforcments. | |
# Do not accept trafic from the client if the IP and mac | |
# are not the same as in the table. | |
# | |
# - Allow clients which match the table. | |
# - Allow all traffic comming from the external interface. | |
# | |
USERS.each do |user, hosts| | |
hosts.each do |ip, mac| | |
puts "#{ARP} -A IN -i #{INT} -d #{GW} -z #{mac} -j ACCEPT" | |
puts "#{ARP} -A IN -i #{INT} -s #{ip} -z #{mac} -j ACCEPT" | |
end | |
end | |
# Accept everything coming from the external | |
# interface. | |
# | |
puts "#{ARP} -A IN -i #{EXT} -j ACCEPT" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment