Created
April 4, 2019 02:40
-
-
Save mathyourlife/7a30516a628fe716107855f86700f718 to your computer and use it in GitHub Desktop.
ASN iptables Block
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
// Add iptable blocks for CIDR blocks associated with the ASN | |
// Each run, the custom chain is flushed and repopulated by the new set of CIDR blocks | |
// | |
// Usage: | |
// asn-block --asn 32934 --asn-name facebook | |
// | |
package main | |
import ( | |
"bytes" | |
"flag" | |
"fmt" | |
"io/ioutil" | |
"log" | |
"net" | |
"os/exec" | |
) | |
var ( | |
iptables = "" | |
ip6tables = "" | |
asn = 0 | |
asnName = "" | |
whois = "" | |
whoisHost = "" | |
) | |
func init() { | |
log.SetFlags(log.Ldate | log.Ltime | log.LUTC | log.Lshortfile) | |
} | |
func main() { | |
parseFlags() | |
// Ensure iptables custom chains exist | |
createCustomChain(iptables) | |
createCustomChain(ip6tables) | |
// Ensure OUTPUT chain jumps to custom chain | |
addOutputJump(iptables) | |
addOutputJump(ip6tables) | |
// Get list of CIDR blocks for the ASN | |
out, err := exec.Command(whois, "-H", "-h", whoisHost, "--", "-F", "-K", "-i", fmt.Sprintf("%d", asn)).Output() | |
if err != nil { | |
log.Fatal(err) | |
} | |
// Flush the custom chain | |
flush(iptables) | |
flush(ip6tables) | |
for _, line := range bytes.Split(out, []byte("\n")) { | |
if !bytes.HasPrefix(line, []byte(fmt.Sprintf("%d\t", asn))) { | |
continue | |
} | |
block(line) | |
} | |
} | |
func parseFlags() { | |
flag.IntVar(&asn, "asn", 0, "ASN to block") | |
flag.StringVar(&asnName, "asn-name", "", "ASN name") | |
flag.StringVar(&whoisHost, "host", "riswhois.ripe.net", "whois host") | |
flag.Parse() | |
if asnName == "" { | |
log.Fatal("missing required --asn-name") | |
} | |
asnName = "asn-block-" + asnName | |
var err error | |
whois, err = exec.LookPath("whois") | |
if err != nil { | |
log.Fatal(err) | |
} | |
iptables, err = exec.LookPath("iptables") | |
if err != nil { | |
log.Fatal(err) | |
} | |
ip6tables, err = exec.LookPath("ip6tables") | |
if err != nil { | |
log.Fatal(err) | |
} | |
} | |
func flush(c string) { | |
out, err := exec.Command(c, "-F", asnName).CombinedOutput() | |
if err != nil { | |
fmt.Printf(string(out)) | |
log.Fatal(err) | |
} | |
} | |
func createCustomChain(c string) { | |
out, err := exec.Command(c, "--new", asnName).CombinedOutput() | |
if err != nil && !bytes.Contains(out, []byte("Chain already exists")) { | |
fmt.Printf(string(out)) | |
log.Fatal(err) | |
} | |
} | |
func addOutputJump(c string) { | |
out, err := exec.Command(c, "-C", "OUTPUT", "-j", asnName).CombinedOutput() | |
if err != nil { | |
if !bytes.Contains(out, []byte("No chain/target/match by that name")) { | |
fmt.Printf(string(out)) | |
log.Fatal(err) | |
} | |
err = exec.Command(c, "-A", "OUTPUT", "-j", asnName).Run() | |
if err != nil { | |
log.Fatal(err) | |
} | |
} | |
} | |
func block(line []byte) { | |
parts := bytes.Split(line, []byte("\t")) | |
if len(parts) != 3 { | |
return | |
} | |
_, _, err := net.ParseCIDR(string(parts[1])) | |
if err != nil { | |
log.Fatal(err) | |
} | |
var cmd *exec.Cmd | |
if bytes.Contains(parts[1], []byte(":")) { | |
cmd = exec.Command(ip6tables, "-A", asnName, "-d", string(parts[1]), "-j", "REJECT") | |
} else { | |
cmd = exec.Command(iptables, "-A", asnName, "-d", string(parts[1]), "-j", "REJECT") | |
} | |
stderr, err := cmd.StderrPipe() | |
if err != nil { | |
log.Fatal(err) | |
} | |
if err := cmd.Start(); err != nil { | |
log.Fatal(err) | |
} | |
slurp, _ := ioutil.ReadAll(stderr) | |
if err := cmd.Wait(); err != nil { | |
fmt.Printf("%s\n", slurp) | |
log.Fatal(err) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment