├── .travis.yml
├── LICENSE
├── README.md
├── binaries
├── config-shield
└── shield
├── config-shield.go
├── example
├── dynamic-vhost.conf
├── le.conf
├── nshield.conf
└── ssl.conf
├── install.sh
├── nshield-scheme.png
├── old
└── nshield-main.py
└── shield.go
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: go
2 | sudo: false
3 | go:
4 | - 1.9.x
5 |
6 | git:
7 | depth: 3
8 |
9 | before_install:
10 | - sudo apt-get -qq update
11 | - go get github.com/BurntSushi/toml
12 |
13 |
14 | install: true
15 |
16 |
17 | go_import_path: github.com/fnzv/net-Shield
18 |
19 | script:
20 | - go build shield.go
21 | - go build config-shield.go
22 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Sami
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## net-Shield
2 | [](https://travis-ci.org/fnzv/net-Shield)
3 | An Easy and Simple Anti-DDoS solution for VPS,Dedicated Servers and IoT devices based on iptables/ipsets
4 |
5 | 
6 |
7 | -----------------
8 |
9 | ## Requirements
10 |
11 | - Linux System with golang, iptables/ipsets
12 | - Nginx
13 |
14 |
15 | ### Quickstart
16 |
17 | Run the bash script (install.sh) to install all the required dependencies.
18 |
19 | ```bash install.sh```
20 |
21 |
22 | You will be prompted to insert a domain and the real IP address associated to it so net-Shield will configure for you the first proxydomain (you can see the changes on /etc/nshield/nshield.conf).
23 |
24 |
25 |
26 | ### Proxy Domains
27 |
28 | To configure proxydomains you need to enable the proxy option on /etc/nshield/nshield.conf (proxy = 1) and be sure that the proxydomain list (on the same conf file) is correct:
29 |
30 | ```
31 | proxydomains = [
32 | "sami.pw 8.8.8.8",
33 | "example.org 1.2.3.4"
34 | ]
35 | ```
36 |
37 |
38 | ### Usage
39 |
40 | After you completed the install with the quickstart script you can call the "config-nshield" commad that will read the nshield.conf and re-configure shield rules based on the new configuration.
41 |
42 | Example:
43 | I want to enable SSL on sami.pw that i just configured as above:
44 | 1) Edit /etc/nshield/nshield.conf and set autossl = 1
45 | 2) On your terminal run: ```# config-shield ```
46 | 3) You can now see the changes on the Nginx configuration
47 |
48 | The domain must point to the net-Shield instance otherwise will fail let's encrypt verification.
49 |
50 | Logs are diplayed on: /var/log/nshield.log
51 |
52 | ## How it works
53 | Basically this script is set by default to run every 30 minutes and execute these operations:
54 |
55 | - Get latest Bot,Spammers,Bad IP/Net reputation lists and blocks if those Bad guys are attacking your server (Thank you FireHol http://iplists.firehol.org/ )
56 | - Enable basic Anti-DDoS methods to deny unwanted/malicious traffic
57 | - Rate limits when under attack
58 | - Allows HTTP(S) Proxying to protect your site
59 |
60 | ## Demo
61 | [](https://asciinema.org/a/zozehdooPDbvem9tCDLI321Hp)
62 |
63 | Tested on Ubuntu 16.04 and 14.04 LTS
64 |
65 | ## Contributors
66 |
67 | Feel free to open issues or send me an email
68 |
69 | ## Binaries
70 |
71 | In case you cannot compile it your self and/or run the install.sh you can find the binaries on:
72 | https://github.com/fnzv/net-Shield/tree/master/binaries
73 |
74 |
75 | ## License
76 |
77 | Code distributed under MIT licence.
78 |
--------------------------------------------------------------------------------
/binaries/config-shield:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fnzv/net-Shield/4198a6d62d7982f6ba1bc2f299506aca111a27ef/binaries/config-shield
--------------------------------------------------------------------------------
/binaries/shield:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fnzv/net-Shield/4198a6d62d7982f6ba1bc2f299506aca111a27ef/binaries/shield
--------------------------------------------------------------------------------
/config-shield.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "os"
5 | "strings"
6 | "log"
7 | "os/exec"
8 |
9 | "github.com/BurntSushi/toml"
10 |
11 | )
12 |
13 | var (
14 |
15 | dryrun int
16 | proxy int
17 | underattack int
18 | basicddos int
19 | autossl int
20 | whitelist []string
21 | proxydomains []string
22 | whitelist_text string
23 |
24 | )
25 |
26 | // Info from config file
27 | type Config struct {
28 | DryRun int
29 | BasicDdos int
30 | UnderAttack int
31 | Proxy int
32 | Autossl int
33 | Whitelist []string
34 | ProxyDomains []string
35 | }
36 | // Reads info from config file
37 | func ReadConfig() Config {
38 | var configfile = "/etc/nshield/nshield.conf"
39 | _, err := os.Stat(configfile)
40 | if err != nil {
41 | log.Fatal("Config file is missing: ", configfile)
42 | }
43 |
44 | var config Config
45 | if _, err := toml.DecodeFile(configfile, &config); err != nil {
46 | log.Fatal(err)
47 | }
48 | //log.Print(config.Index)
49 | return config
50 | }
51 |
52 | func exec_shell(command string) string {
53 | out, err := exec.Command("/bin/bash","-c",command).Output()
54 | if err != nil {
55 | log.Fatal(err)
56 | }
57 | return string(out)
58 | }
59 |
60 |
61 |
62 | func main() {
63 |
64 | var config = ReadConfig()
65 | basicddos = config.BasicDdos
66 | underattack = config.UnderAttack
67 | dryrun = config.DryRun
68 | proxy = config.Proxy
69 | autossl = config.Autossl
70 | whitelist = config.Whitelist
71 | proxydomains = config.ProxyDomains
72 |
73 |
74 | f, err := os.OpenFile("/var/log/nshield.log", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
75 | if err != nil {
76 | log.Fatal(err)
77 | }
78 | defer f.Close()
79 | log.SetOutput(f)
80 |
81 |
82 | log.Println("Loading nshield with these settings:")
83 | log.Println("BasicDdos: ",basicddos)
84 | log.Println("UnderAttack: ",underattack)
85 | log.Println("DryRun: ",dryrun)
86 | log.Println("Proxy: ",proxy)
87 |
88 |
89 | exec_shell("wget -O /etc/nshield/ipsets/firehol_level1.netset https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/firehol_level1.netset >/dev/null 2>&1")
90 | exec_shell("wget -O /etc/nshield/ipsets/botscout_1d.ipset https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/botscout_1d.ipset >/dev/null 2>&1")
91 | exec_shell("wget -O /etc/nshield/ipsets/bi_any_2_30d.ipset https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/bi_any_2_30d.ipset >/dev/null 2>&1")
92 | exec_shell("wget -O /etc/nshield/snort_ipfilter.ipset https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/snort_ipfilter.ipset >/dev/null 2>&1")
93 |
94 | exec_shell("iptables -F")
95 | log.Println("Cleaning iptables..")
96 | // check if already exists
97 | check_ipset := exec_shell("ipset list | grep -e rate -e block | awk '{print $2}'")
98 | if strings.Contains(check_ipset,"rate") {
99 | log.Println("ipset already existing")
100 | } else {
101 | log.Println("creating ipset")
102 | exec_shell("ipset create ratelimit hash:ip hashsize 4096")
103 | }
104 |
105 | if strings.Contains(check_ipset,"block") {
106 | log.Println("ipset already existing")
107 | } else {
108 | log.Println("creating ipset")
109 | exec_shell("ipset create block hash:ip timeout 0")
110 | }
111 | exec_shell("iptables -A INPUT -m set --match-set ratelimit src -m hashlimit --hashlimit 25/sec --hashlimit-name ratelimithash -j DROP")
112 | exec_shell("iptables -A INPUT -m set --match-set block src -j DROP")
113 |
114 |
115 |
116 |
117 | i1 := 0
118 | for range whitelist {
119 | log.Println("Adding to whitelist: "+whitelist[i1])
120 | whitelist_text = whitelist_text + whitelist[i1]
121 | //fmt.Printf("%s", out)
122 | if dryrun == 0 {
123 | exec_shell("iptables -I INPUT -s "+whitelist[i1]+" -j ACCEPT -m comment --comment 'WHITELISTED IP - NSHIELD'")
124 | }
125 | i1++
126 | }
127 |
128 |
129 |
130 | log.Println("Setting ipt logs..")
131 | exec_shell(`iptables -I INPUT -m limit --limit 40/min -j LOG --log-prefix "nShield: " --log-level 7`)
132 |
133 | if (basicddos == 1 && dryrun == 0) {
134 | log.Println("Setting up Basic DDos Protection")
135 | exec_shell("iptables -A INPUT -p tcp ! --syn -m state --state NEW -j DROP")
136 | exec_shell("iptables -A INPUT -p tcp --tcp-flags ALL ALL -j DROP")
137 | exec_shell("iptables -A INPUT -p icmp -m icmp --icmp-type timestamp-request -j DROP && iptables -A INPUT -p icmp -m limit --limit 1/second -j ACCEPT")
138 | exec_shell("/sbin/sysctl -w net/netfilter/nf_conntrack_tcp_loose=0")
139 | exec_shell("echo 1000000 > /sys/module/nf_conntrack/parameters/hashsize && /sbin/sysctl -w net/netfilter/nf_conntrack_max=2000000 && /sbin/sysctl -w net.ipv4.tcp_syn_retries=2 && /sbin/sysctl -w net.ipv4.tcp_rfc1337=1 && /sbin/sysctl -w net.ipv4.tcp_synack_retries=1")
140 |
141 | }
142 |
143 |
144 | if (underattack == 1 && dryrun ==0) {
145 | exec_shell("iptables -A INPUT -p tcp --syn -m hashlimit --hashlimit 15/s --hashlimit-burst 30 --hashlimit-mode srcip --hashlimit-name synattack -j ACCEPT && iptables -A INPUT -p tcp --syn -j DROP")
146 | }
147 |
148 |
149 | if (proxy == 1 && dryrun ==0) {
150 | log.Println("Setting up nShield proxy for domains found in configuration")
151 | i:= 0
152 | for range proxydomains {
153 | log.Println(proxydomains[i])
154 | s := strings.Split(proxydomains[i], " ")
155 | domain, ip := s[0], s[1]
156 | log.Println("Generating Nginx conf for "+domain+" on IP "+ip)
157 | //fmt.Printf("%s", out)
158 | if strings.Contains(exec_shell("cat /etc/nginx/sites-enabled/dynamic-vhost.conf"),domain) == false {
159 | if dryrun == 0 {
160 | exec_shell(`echo 'server {
161 | listen 80;
162 | root /var/www/html;
163 | index index.html index.htm index.nginx-debian.html;
164 | server_name `+domain+`;
165 | location / {
166 | proxy_pass http://`+ip+`;
167 | proxy_set_header Host $host;
168 | proxy_set_header X-Real-IP $remote_addr;
169 | }
170 | }
171 | ' >> /etc/nginx/sites-enabled/dynamic-vhost.conf`)
172 | exec_shell("service nginx reload")
173 | }
174 |
175 | } else { log.Println("Domain already present") }
176 | i++
177 | }
178 | }
179 |
180 | if (autossl ==1 && dryrun == 0) {
181 |
182 | i2 :=0
183 | for range proxydomains {
184 | log.Println(proxydomains[i2])
185 | s := strings.Split(proxydomains[i2], " ")
186 | domain, ip := s[0], s[1]
187 | if strings.Contains(exec_shell("cat /etc/nginx/sites-enabled/dynamic-ssl-vhost.conf"),domain) == false {
188 | log.Println("i will generate SSL cert with certbot for ",domain)
189 | //call certbot
190 | exec_shell("certbot certonly --webroot --agree-tos --no-eff-email -n -w /var/www/letsencrypt -d "+domain)
191 |
192 | exec_shell(`echo 'server {
193 | listen 443 ssl;
194 | root /var/www/html;
195 | index index.html index.htm index.nginx-debian.html;
196 | ssl_certificate /etc/letsencrypt/live/`+domain+`/cert.pem;
197 | ssl_certificate_key /etc/letsencrypt/live/`+domain+`/privkey.pem;
198 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
199 | ssl_ciphers HIGH:!aNULL:!MD5;
200 | server_name `+domain+`;
201 | location / {
202 | proxy_pass http://`+ip+`;
203 | proxy_set_header Host $host;
204 | proxy_set_header X-Real-IP $remote_addr;
205 | }
206 | }
207 | ' >> /etc/nginx/sites-enabled/dynamic-ssl-vhost.conf && service nginx reload`)
208 |
209 | }
210 |
211 | i2++
212 | }
213 |
214 | }
215 |
216 | log.Println("Top current connections: \n ",exec_shell(`netstat -atun | grep -v "Addr" | grep -v "and" | awk '{print $5}' | cut -d: -f1 | sed -e '/^$/d' |sort | uniq -c | sort -n`))
217 |
218 | }
219 |
--------------------------------------------------------------------------------
/example/dynamic-vhost.conf:
--------------------------------------------------------------------------------
1 | server {
2 | listen 80 default_server;
3 |
4 | root /var/www/html;
5 | index index.html;
6 |
7 | server_name _;
8 |
9 | location / {
10 | proxy_pass http://domain;
11 | proxy_set_header Host $host;
12 | proxy_set_header X-Real-IP $remote_addr;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/example/le.conf:
--------------------------------------------------------------------------------
1 | location ^~ /.well-known/acme-challenge/ {
2 | default_type "text/plain";
3 | root /var/www/letsencrypt;
4 | }
5 |
--------------------------------------------------------------------------------
/example/nshield.conf:
--------------------------------------------------------------------------------
1 | dryrun= 0
2 | basicddos = 1
3 | underattack = 1
4 | proxy = 1
5 | autossl = 0
6 | whitelist = [
7 | "192.168.0.0/24",
8 | "127.0.0.1/8"
9 | ]
10 | proxydomains = [
11 | "example.org 1.2.3.4"
12 | ]
13 |
--------------------------------------------------------------------------------
/example/ssl.conf:
--------------------------------------------------------------------------------
1 | ssl_session_timeout 1d;
2 | ssl_session_cache shared:SSL:50m;
3 | ssl_session_tickets off;
4 |
5 | ssl_protocols TLSv1.2;
6 | ssl_ciphers EECDH+AESGCM:EECDH+AES;
7 | ssl_ecdh_curve secp384r1;
8 | ssl_prefer_server_ciphers on;
9 |
10 | ssl_stapling on;
11 | ssl_stapling_verify on;
12 |
13 | add_header Strict-Transport-Security "max-age=15768000; includeSubdomains; preload";
14 | add_header X-Frame-Options DENY;
15 | add_header X-Content-Type-Options nosniff;
16 |
--------------------------------------------------------------------------------
/install.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | echo "Downloading & Installing Golang.. \n"
4 |
5 | # Golang quick install
6 |
7 | apt-get update
8 | wget https://storage.googleapis.com/golang/go1.9.2.linux-amd64.tar.gz
9 | sudo tar -xvf go1.9.2.linux-amd64.tar.gz
10 | sudo mv go /usr/local
11 | echo "export GOROOT=/usr/local/go" >> /root/.bashrc
12 | echo "export GOPATH=$HOME/Projects" >> /root/.bashrc
13 | echo "export PATH=$GOPATH/bin:$GOROOT/bin:$PATH" >> /root/.bashrc
14 | echo "Checking Golang version\n"
15 | ln -s /usr/local/go/bin/go /usr/bin/go
16 | go get github.com/BurntSushi/toml
17 | rm -rf go/
18 |
19 | rm -rf go1.9.2.linux-amd64.tar.gz
20 | mkdir -p /etc/nshield/ipsets/
21 |
22 | apt-get install -y jq software-properties-common ipset
23 | sudo add-apt-repository -y ppa:certbot/certbot
24 | sudo apt-get update
25 | sudo apt-get install python-certbot-nginx -y
26 | touch /etc/nginx/sites-enabled/dynamic-ssl-vhost.conf
27 | touch /etc/nginx/sites-enabled/dynamic-vhost.conf
28 |
29 | echo 'Setting ipt new log file..'
30 | # Configures ipt connection logging to separate file
31 | echo '# Log kernel generated iptables log messages to file
32 | :msg,contains,"nShield" /var/log/iptables.log
33 | & ~' >> /etc/rsyslog.d/10-ipt.conf && service rsyslog restart
34 |
35 | echo "/var/log/iptables.log {
36 | maxsize 100M
37 | hourly
38 | missingok
39 | rotate 4
40 | compress
41 | notifempty
42 | nocreate
43 | }" > /etc/logrotate.d/nshield
44 |
45 |
46 | echo "Installing Nginx for nShield proxy..\n"
47 | apt install -y nginx
48 |
49 |
50 |
51 | echo "Copying example configuration... \n"
52 |
53 | wget -O /etc/nshield/nshield.conf https://raw.githubusercontent.com/fnzv/nShield/master/example/nshield.conf
54 | wget -O /etc/nginx/snippet/ssl.conf https://raw.githubusercontent.com/fnzv/nShield/master/example/ssl.conf
55 | wget -O /etc/nginx/snippet/le.conf https://raw.githubusercontent.com/fnzv/nShield/master/example/le.conf
56 |
57 | read -p "Enter a domain to protect: " domain
58 |
59 | read -p "Enter the real IP address of the website: " ip
60 |
61 | sed -i s"/example.org/$domain/"g /etc/nshield/nshield.conf
62 |
63 | sed -i s"/1.2.3.4/$ip/"g /etc/nshield/nshield.conf
64 |
65 |
66 | echo "Compiling source code.."
67 |
68 | go build shield.go
69 |
70 | go build config-shield.go
71 |
72 | cp config-shield /bin/config-shield
73 | cp shield /bin/shield
74 |
75 | echo "30 * * * * /bin/shield" >> /etc/crontab
76 |
--------------------------------------------------------------------------------
/nshield-scheme.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fnzv/net-Shield/4198a6d62d7982f6ba1bc2f299506aca111a27ef/nshield-scheme.png
--------------------------------------------------------------------------------
/old/nshield-main.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # Author: Sami Yessou - samiii@protonmail.com
3 | # nShield - An Easy and Simple Anti-DDoS solution for VPS,Dedicated Servers and IoT devices
4 | # (To be)*Features: Blocks known attackers from the Web and allows users to CDN/Proxying their site with an offsite VPS/Servers
5 | # Still in beta
6 |
7 |
8 | import os,argparse,ConfigParser,sys
9 |
10 | config = ConfigParser.ConfigParser()
11 |
12 | config.read("/etc/nshield/nshield.conf")
13 |
14 |
15 | # Log check
16 | os.popen('find /var/log/syslog -type f -size +500k -delete >/dev/null 2>&1')
17 |
18 | #read conf and save variables
19 | dryrun = int(config.get("conf","dryrun"))
20 | basic_ddos = int(config.get("conf","basic_ddos"))
21 | under_attack = int(config.get("conf","under_attack"))
22 | nshield_proxy = int(config.get("conf","nshield_proxy"))
23 |
24 | #print "Configuration loaded: \n"
25 | #print "dryrun: "+dryrun
26 | #print "\nbasic_ddos: "+basic_ddos
27 | #print "\nunder_attack: "+under_attack
28 | #print "\nnshield_proxy: "+nshield_proxy
29 |
30 |
31 | parser = argparse.ArgumentParser()
32 |
33 | parser.add_argument('-ssl', action='store_true', default=False,dest='autossl', help='Enable SSL on proxy domains')
34 |
35 | parser.add_argument('-dry', action='store_true', default=False,dest='standalone', help='Standalone mode')
36 |
37 | results = parser.parse_args()
38 |
39 |
40 |
41 | if results.standalone:
42 | dryrun = 1
43 | print "Running nShield in standalone mode.. Dryrun is now enabled for safety\n"
44 | autossl = results.autossl
45 |
46 |
47 |
48 |
49 |
50 | #Update firehol ip/netsets
51 |
52 | os.popen("wget -O firehol_level1.netset https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/firehol_level1.netset >/dev/null 2>&1")
53 | os.popen("wget -O botscout_1d.ipset https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/botscout_1d.ipset >/dev/null 2>&1")
54 | os.popen("wget -O bi_any_2_30d.ipset https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/bi_any_2_30d.ipset >/dev/null 2>&1")
55 | os.popen("wget -O snort_ipfilter.ipset https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/snort_ipfilter.ipset >/dev/null 2>&1")
56 |
57 | #Load all sets from cwd
58 | blocklist_ipset=os.popen("cat *.ipset").read()
59 | blocklist_netset=os.popen("cat *.netset").read()
60 | whitelist=os.popen("cat /etc/nshield/whitelist").read()
61 |
62 | # Get top 10 Nginx reqs
63 | nginx_iplist=os.popen("cat /var/log/nginx/access.log | awk ' { print $1}' | sort -n | uniq -c | sort -rn | head").read()
64 |
65 |
66 | splitted_nginx_iplist = nginx_iplist.split()
67 |
68 |
69 | # For every IP check ASN & Reputation
70 |
71 | print "Top 10 NGINX Requests are coming from these IPs : \n"+nginx_iplist
72 |
73 |
74 | print "Top 10 ASN by NGINX Requests: \n"
75 | for ip in splitted_nginx_iplist:
76 | if "." in ip:
77 | print ip+" - MNT BY: "+os.popen("curl -s ipinfo.io/"+ip+"/org").read()
78 | if dryrun is 1:
79 | os.popen("iptables -F")
80 | os.popen('iptables -I INPUT -j LOG --log-prefix "nShield: " --log-level 7')
81 | ipt_iplist=os.popen("cat /var/log/nshield.log | awk '{ print $12 }' | sed s'/SRC=//' | sort -n | uniq -c | grep -v DST").read()
82 | top_ipt_iplist=os.popen("cat /var/log/nshield.log | awk '{ print $12 }' | sed s'/SRC=//' | sort -n | uniq -c | sort -rn | grep -v DST | head").read()
83 | splitted_ipt_iplist=ipt_iplist.split()
84 | splitted_top_ipt_iplist=top_ipt_iplist.split()
85 |
86 | print "Top 10 TCP Requests are coming from these IPs : \n"+top_ipt_iplist
87 |
88 | print "Top 10 ASN of ipt logged Requests: \n"
89 | for ip in splitted_top_ipt_iplist:
90 | if "." in ip:
91 | print ip+" - MNT BY: "+os.popen("curl -s ipinfo.io/"+ip+"/org").read()
92 |
93 |
94 |
95 | for ip in splitted_ipt_iplist:
96 | if "." in ip:
97 | if ip in blocklist_ipset and conns >= 10:
98 | print "Blocking "+ip+" because found in ipsets and more than 10 reqs"
99 | iptblock="iptables -I INPUT -s "+ip+" -m comment --comment nShield-Blocked-from-ipset+10reqs -j DROP"
100 | if dryrun is 1:
101 | print "Dry Run.."
102 | else:
103 | os.popen(iptblock)
104 | subnet=ip.split('.')
105 | netset=subnet[0]+"."+subnet[1]+"."+subnet[2]
106 | if netset in blocklist_netset:
107 | print "Blocking "+ip+" because found in netsets"
108 | iptblock="iptables -I INPUT -s "+netset+".0/24 -m comment --comment nShield-Blocked-from-netsets -j DROP"
109 | if dryrun is 1:
110 | print "Dry Run.."
111 | else:
112 | os.popen(iptblock)
113 | else:
114 | conns=ip
115 |
116 |
117 |
118 |
119 | if dryrun is not 1:
120 | print "Setting up whitelist .."
121 | os.popen("iptables -I INPUT -i lo -j ACCEPT && iptables -I INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT")
122 | #check if its real ip before
123 | for ip in whitelist.split():
124 | print ip
125 | os.popen("iptables -I INPUT -s "+ip+" -j ACCEPT -m comment --comment nShield-whitelist")
126 |
127 |
128 |
129 | if basic_ddos is 1 and dryrun is 0:
130 | print "Setting up Basic DDoS Protection"
131 |
132 | # Block SYN FLOOD
133 | os.popen("iptables -A INPUT -p tcp ! --syn -m state --state NEW -j DROP")
134 | # Block XMAS Scan
135 | os.popen("iptables -A INPUT -p tcp --tcp-flags ALL ALL -j DROP")
136 | # Smurf attack protection
137 | os.popen("iptables -A INPUT -p icmp -m icmp --icmp-type timestamp-request -j DROP && iptables -A INPUT -p icmp -m limit --limit 1/second -j ACCEPT")
138 |
139 | os.popen("/sbin/sysctl -w net/netfilter/nf_conntrack_tcp_loose=0")
140 |
141 | os .popen("echo 1000000 > /sys/module/nf_conntrack/parameters/hashsize && /sbin/sysctl -w net/netfilter/nf_conntrack_max=2000000 && /sbin/sysctl -w net.ipv4.tcp_syn_retries=2 && /sbin/sysctl -w net.ipv4.tcp_rfc1337=1 && /sbin/sysctl -w net.ipv4.tcp_synack_retries=1")
142 |
143 | print "\nBlocking XMAS scan, Smurf, ICMP attacks & SYN flood"
144 |
145 |
146 |
147 | if under_attack is 1 and dryrun is 0:
148 | # burst connections and add rate limits
149 | os.popen('iptables -A INPUT -p tcp --syn -m hashlimit --hashlimit 15/s --hashlimit-burst 30 --hashlimit-mode srcip --hashlimit-name synattack -j ACCEPT && iptables -A INPUT -p tcp --syn -j DROP')
150 |
151 |
152 |
153 | if nshield_proxy is 1 and dryrun is 0:
154 | print "Setting up nShield proxy for domains found in /etc/nshield/proxydomains\n"
155 | # Generates nginx proxy_pass from /etc/nshield/proxydomains and checks if already present in nginx conf
156 | with open("/etc/nshield/proxydomains") as f:
157 | for line in f:
158 | print "LINE"
159 | line = line.split(' ')
160 | domain = str(line[0])
161 | ip = line[1]
162 | if domain not in os.popen("cat /etc/nginx/sites-enabled/dynamic-vhost.conf").read():
163 | print "I Will generate proxy configuration for site "+domain+" on IP: "+ip
164 | os.popen("""echo 'server {
165 | listen 80;
166 |
167 | root /var/www/html;
168 | index index.html index.htm index.nginx-debian.html;
169 |
170 | server_name """+domain+""";
171 |
172 | location / {
173 | proxy_pass http://"""+ip+""";
174 | proxy_set_header Host $host;
175 | proxy_set_header X-Real-IP $remote_addr;
176 | }
177 | }
178 | ' >> /etc/nginx/sites-enabled/dynamic-vhost.conf""")
179 | os.popen('service nginx restart')
180 | else:
181 | print "Domain already configured"
182 |
183 | print "Now you can test that your site is reachable via nShield proxy by changing the domain DNS or via your PC hosts file or directly DNS A record"
184 |
185 |
186 | # Is triggered only if run from commandline and not cron
187 | if autossl and dryrun is 0:
188 | with open("/etc/nshield/proxydomains") as f:
189 | content = f.readlines()
190 | content1 = content[0].split(' ')
191 | ip = content1[1].strip('\n')
192 | domain = content1[0]
193 | if domain not in os.popen("cat /etc/nginx/sites-enabled/dynamic-ssl-vhost.conf").read():
194 | print "I Will generate SSL certs for "+domain+" with Let's Encrypt DNS challenge"
195 | email = str(raw_input("Insert your email address? (Used for cert Expiration and Let's Encrypt TOS agreement \n"))
196 | os.system("certbot --text --agree-tos --email "+email+" -d "+domain+" --manual --preferred-challenges dns --expand --renew-by-default --manual-public-ip-logging-ok certonly")
197 | print "Setting up Nginx configuration...\n"
198 | os.popen("""echo 'server {
199 | listen 443 ssl;
200 |
201 | root /var/www/html;
202 | index index.html index.htm index.nginx-debian.html;
203 | ssl_certificate /etc/letsencrypt/live/"""+domain+"""/cert.pem;
204 | ssl_certificate_key /etc/letsencrypt/live/"""+domain+"""/privkey.pem;
205 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
206 | ssl_ciphers HIGH:!aNULL:!MD5;
207 | server_name """+domain+""";
208 |
209 | location / {
210 | proxy_pass http://"""+ip+""";
211 | proxy_set_header Host $host;
212 | proxy_set_header X-Real-IP $remote_addr;
213 | }
214 | }
215 | ' >> /etc/nginx/sites-enabled/dynamic-ssl-vhost.conf && service nginx restart""")
216 |
217 | print "TOP Current Connections by IP \n"
218 |
219 | print os.popen("""netstat -atun | grep -v "Addr" | grep -v "and" | awk '{print $5}' | cut -d: -f1 | sed -e '/^$/d' |sort | uniq -c | sort -n""").read()
220 |
--------------------------------------------------------------------------------
/shield.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "os"
5 | "strings"
6 | "log"
7 | "os/exec"
8 |
9 | "github.com/BurntSushi/toml"
10 |
11 | )
12 |
13 | var (
14 |
15 | dryrun int
16 | proxy int
17 | underattack int
18 | basicddos int
19 | autossl int
20 | whitelist []string
21 | proxydomains []string
22 | whitelist_text string
23 |
24 | )
25 |
26 | // Info from config file
27 | type Config struct {
28 | DryRun int
29 | BasicDdos int
30 | UnderAttack int
31 | Proxy int
32 | Autossl int
33 | Whitelist []string
34 | ProxyDomains []string
35 | }
36 | // Reads info from config file
37 | func ReadConfig() Config {
38 | var configfile = "/etc/nshield/nshield.conf"
39 | _, err := os.Stat(configfile)
40 | if err != nil {
41 | log.Fatal("Config file is missing: ", configfile)
42 | }
43 |
44 | var config Config
45 | if _, err := toml.DecodeFile(configfile, &config); err != nil {
46 | log.Fatal(err)
47 | }
48 | //log.Print(config.Index)
49 | return config
50 | }
51 |
52 | func exec_shell(command string) string {
53 | out, err := exec.Command("/bin/bash","-c",command).Output()
54 | if err != nil {
55 | log.Fatal(err)
56 | }
57 | return string(out)
58 | }
59 |
60 |
61 |
62 | func main() {
63 |
64 | var config = ReadConfig()
65 | basicddos = config.BasicDdos
66 | underattack = config.UnderAttack
67 | dryrun = config.DryRun
68 | proxy = config.Proxy
69 | autossl = config.Autossl
70 | whitelist = config.Whitelist
71 | proxydomains = config.ProxyDomains
72 | exec_shell("wget -O /etc/nshield/ipsets/firehol_level1.netset https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/firehol_level1.netset >/dev/null 2>&1")
73 | exec_shell("wget -O /etc/nshield/ipsets/botscout_1d.ipset https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/botscout_1d.ipset >/dev/null 2>&1")
74 | exec_shell("wget -O /etc/nshield/ipsets/bi_any_2_30d.ipset https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/bi_any_2_30d.ipset >/dev/null 2>&1")
75 | exec_shell("wget -O /etc/nshield/snort_ipfilter.ipset https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/snort_ipfilter.ipset >/dev/null 2>&1")
76 |
77 | f, err := os.OpenFile("/var/log/nshield.log", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
78 | if err != nil {
79 | log.Fatal(err)
80 | }
81 | defer f.Close()
82 | log.SetOutput(f)
83 |
84 |
85 | blocklist_ipset:=exec_shell("cat /etc/nshield/ipsets/*.ipset")
86 | blocklist_netset:=exec_shell("cat /etc/nshield/ipsets/*.netset")
87 |
88 | iplist:=exec_shell("cat /var/log/iptables.log | awk ' { print $11 } ' | sed s'/SRC=//'g | sort -n | uniq -c | sort -rn | head -n25 | grep -v 192.168. | awk '{ print $2 }'")
89 |
90 |
91 | log.Println("Top incoming requests are: \n"+iplist)
92 |
93 | // resolve with curl https://api.iptoasn.com/v1/as/ip/8.8.8.8 | jq '.as_description'
94 |
95 | // Split on comma.
96 | splitted_iplist := strings.Split(iplist, " ")
97 |
98 | // Display all elements.
99 | for i := range splitted_iplist {
100 | ip:=splitted_iplist[i]
101 | if strings.Contains(blocklist_ipset,ip) {
102 | log.Println("Banning "+ip+" because found in IP blocklists")
103 | exec_shell("ipset add block "+ip+" timeout 300")
104 | }
105 | network:=exec_shell(`echo "+ip+" | awk -F '.' '{ print $1"."$2"."$3 }'`)
106 | if strings.Contains(blocklist_netset,network) {
107 | log.Println("Banning "+ip+" because found in Net blocklists")
108 | exec_shell("ipset add block "+ip+" timeout 300")
109 | }
110 | //
111 |
112 |
113 |
114 | }
115 | }
116 |
--------------------------------------------------------------------------------