Skip to content

Instantly share code, notes, and snippets.

@mathyourlife
Created April 4, 2019 02:40
Show Gist options
  • Save mathyourlife/7a30516a628fe716107855f86700f718 to your computer and use it in GitHub Desktop.
Save mathyourlife/7a30516a628fe716107855f86700f718 to your computer and use it in GitHub Desktop.
ASN iptables Block
// 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