Commit d15666a9 authored by SR's avatar SR
Browse files

Initial commit

parents
.idea/
gotiklist
# Binaries for programs and plugins
*.exe
*.dll
*.so
*.dylib
# Test binary, build with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
.glide/
package main
import (
"bufio"
"flag"
"fmt"
"io"
"log"
"net"
"net/http"
"os"
"strconv"
"strings"
"time"
"unicode"
"gopkg.in/routeros.v2"
)
func myUsage() {
fmt.Printf("Usage: %s [OPTIONS] PATH\nPATH can point to a local file or be a http/https link.\n\nOPTIONS:\n", os.Args[0])
flag.PrintDefaults()
}
var (
address = flag.String("address", "192.168.1.1:8728", "Address")
username = flag.String("username", "admin", "Username")
password = flag.String("password", "", "Password")
daemon = flag.Bool("daemon", false, "Demon")
interval = flag.Duration("interval", 7200*time.Second, "Interval (in seconds)")
list = flag.String("list", "rk", "List name")
checkotherlists = flag.Bool("checkotherlists", true, "Check is other lists contain the address")
remove = flag.Bool("remove", true, "Remove addresses from the router that are not in the local list")
allowdomains = flag.Bool("allowdomains", false, "Allow domain names in the list")
allowempty = flag.Bool("allowempty", false, "Allow empty list")
listprint = flag.Bool("listprint", false, "Print the list")
)
func main() {
flag.Usage = myUsage
flag.Parse()
if *listprint {
c, err := routeros.Dial(*address, *username, *password)
if err != nil {
log.Println(err)
} else {
reply, err := c.Run("/ip/firewall/address-list/print", "?list="+*list, "=.proplist=.id,address")
if err != nil {
log.Println(err)
} else {
//log.Println("Router list length:", len(reply.Re))
if *listprint {
for _, re := range reply.Re {
log.Println(re.Map["address"])
}
}
}
}
return
}
var srcPath string
if len(flag.Args()) == 1 {
srcPath = flag.Args()[0]
} else {
srcPath = "https://reestr.rublacklist.net/api/v2/ips/csv"
}
log.Println(srcPath)
for {
log.Println("Sync start")
c, err := routeros.Dial(*address, *username, *password)
if err != nil {
log.Println(err)
} else {
var ipl map[string]struct{}
if strings.HasPrefix(srcPath, "http://") || strings.HasPrefix(srcPath, "https://") {
ipl, err = downloadIP(srcPath)
} else {
ipl, err = readIP(srcPath)
if err == io.EOF {
err = nil
}
if err != nil {
log.Println(err)
return
}
}
log.Println("List length:", len(ipl))
if *allowempty == false {
if len(ipl) <= 0 {
log.Println("List is empty and allowempty option is not enabled. Exiting.")
return
}
}
var idsn int
idsn = 0
if *checkotherlists {
reply, err := c.Run("/ip/firewall/address-list/print", "?list="+*list, "?#!", "=.proplist=.id,address")
if err != nil {
log.Println(err)
} else {
for _, re := range reply.Re {
if _, ok := ipl[re.Map["address"]]; ok {
delete(ipl, re.Map["address"])
}
}
}
}
reply, err := c.Run("/ip/firewall/address-list/print", "?list="+*list, "=.proplist=.id,address")
if err != nil {
log.Println(err)
} else {
log.Println("Router list length:", len(reply.Re))
for _, re := range reply.Re {
if _, ok := ipl[re.Map["address"]]; ok {
delete(ipl, re.Map["address"])
} else {
if *remove {
idsn++
reply, err = c.Run("/ip/firewall/address-list/remove", "=.id="+re.Map[".id"])
if err != nil {
log.Println(err)
}
}
}
}
log.Println("Removals:", idsn)
log.Println("Additions:", len(ipl))
for key, _ := range ipl {
if CheckIP(key) {
reply, err = c.Run("/ip/firewall/address-list/add", "=disabled=false", "=list="+*list, "=address="+key)
if err != nil {
log.Println(err)
}
}
}
}
c.Close()
}
log.Println("Sync end")
if *daemon {
time.Sleep(*interval)
} else {
return
}
}
}
func decodeIPs(r *bufio.Reader) map[string]struct{} {
strs := make(map[string]struct{})
var stIP string
stIP = ""
x, err := r.ReadByte()
for err == nil {
if x == '"' {
x, err = r.ReadByte()
continue
}
if x == ';' || x == ',' || x == '\n' {
stIP = RemoveSpaceMap(stIP)
stIP = RemoveComments(stIP)
if stIP != "" {
if CheckIP(stIP) {
strs[stIP] = struct{}{}
}
}
stIP = ""
x, err = r.ReadByte()
continue
}
stIP += string(x)
x, err = r.ReadByte()
}
if stIP != "" {
stIP = RemoveSpaceMap(stIP)
stIP = RemoveComments(stIP)
if CheckIP(stIP) {
strs[stIP] = struct{}{}
}
}
return strs
}
func downloadIP(url string) (strs map[string]struct{}, err error) {
var netClient = &http.Client{
Timeout: time.Second * 120,
}
response, err := netClient.Get(url)
if err != nil {
return
} else {
defer response.Body.Close()
r := bufio.NewReader(response.Body)
strs = decodeIPs(r)
}
return
}
func readIP(filename string) (strs map[string]struct{}, err error) {
f, err := os.Open(filename)
defer f.Close()
if err != nil {
return
}
r := bufio.NewReader(f)
strs = decodeIPs(r)
return
}
func RemoveSpaceMap(str string) string {
return strings.Map(func(r rune) rune {
if unicode.IsSpace(r) {
return -1
}
return r
}, str)
}
func RemoveSpaceFieldsJoin(str string) string {
return strings.Join(strings.Fields(str), "")
}
func RemoveComments(s string) string {
if idx := strings.Index(s, "#"); idx != -1 {
return s[:idx]
}
return s
}
func CheckIP(stIP string) bool {
if *allowdomains {
return true
}
var stIPc string
if strings.Contains(stIP, "/") {
nmsplit := strings.Index(stIP, "/")
stIPc = stIP[:nmsplit]
stIPnm, err := strconv.Atoi(stIP[nmsplit+1:])
if err != nil {
log.Println("Not an IPv4 address:", stIP)
return false
}
if stIPnm > 32 && stIPnm < 0 {
log.Println("Not an IPv4 address:", stIP)
return false
}
} else {
stIPc = stIP
}
trial := net.ParseIP(stIPc)
if trial.To4() == nil {
log.Println("Not an IPv4 address:", stIP)
return false
}
return true
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment