From 9b29b1dc30ca57e627195b2238a4fd5b68455b55 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Tue, 17 Apr 2018 13:55:43 -0400 Subject: initial commit --- influxdb.go | 17 +++++++++ main.go | 75 ++++++++++++++++++++++++++++++++++++ tinc.go | 125 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 217 insertions(+) create mode 100644 influxdb.go create mode 100644 main.go create mode 100644 tinc.go diff --git a/influxdb.go b/influxdb.go new file mode 100644 index 0000000..992bef3 --- /dev/null +++ b/influxdb.go @@ -0,0 +1,17 @@ +package main + +import ( + "time" + + client "github.com/influxdata/influxdb/client/v2" +) + +type Point = *client.Point + +func NewPoint(name string, tags map[string]string, fields map[string]interface{}) Point { + pt, err := client.NewPoint(name, tags, fields, time.Now()) + if err != nil { + panic(err) + } + return pt +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..a4f31c3 --- /dev/null +++ b/main.go @@ -0,0 +1,75 @@ +package main + +import ( + "fmt" + "io/ioutil" + "net" + "os" + "path/filepath" + "strings" + "sync" +) + +var wg sync.WaitGroup + +func Emit(pt Point) { + if pt == nil { + return + } + fmt.Println(pt) +} + +func DoHostfile(fname string) { + defer wg.Done() + hostname := filepath.Base(fname) + cfg, err := readConfigFile(fname) + if err != nil { + Emit(NewPoint("public", map[string]string{"host":hostname}, map[string]interface{}{"error": err.Error()})) + return + } + for _, address := range getAddresses(cfg) { + wg.Add(2) + go Emit(DoAddress(hostname, "tcp4", address)) + go Emit(DoAddress(hostname, "tcp6", address)) + } +} + +func DoAddress(host, network, address string) Point { + defer wg.Done() + tags := map[string]string{ + "host": host, + "network": network, + "address": address, + } + + addr, err := net.ResolveTCPAddr(network, address) + if err != nil { + if ae, ok := err.(*net.AddrError); ok && ae.Err == "no suitable address found" { + return nil + } + return NewPoint("public", tags, map[string]interface{}{"error": err.Error()}) + } + conn, err := net.DialTCP(network, nil, addr) + if err != nil { + return NewPoint("public", tags, map[string]interface{}{"error": err.Error()}) + } + conn.CloseWrite() + all, _ := ioutil.ReadAll(conn) + line := strings.TrimRight(string(all), "\n") + parts := strings.Split(line, " ") + if len(parts) != 3 { + return NewPoint("public", tags, map[string]interface{}{"error": fmt.Sprintf("malformed ID line: %q", line)}) + } + return NewPoint("public", tags, map[string]interface{}{ + "name": parts[1], + "version": parts[2], + }) +} + +func main() { + for _, fname := range os.Args[1:] { + wg.Add(1) + go DoHostfile(fname) + } + wg.Wait() +} diff --git a/tinc.go b/tinc.go new file mode 100644 index 0000000..76857cb --- /dev/null +++ b/tinc.go @@ -0,0 +1,125 @@ +package main + +import ( + "bufio" + "fmt" + "net" + "os" + "strings" +) + +type Error struct { + File string + Line int + Err error +} + +func (e Error) Error() string { + if e.Line > 0 { + return fmt.Sprintf("%v:%v: %v", e.File, e.Line, e.Err) + } else { + return fmt.Sprintf("%v: %v", e.File, e.Err) + } +} + +func parseConfigLine(line string) (key, val string) { + line = strings.TrimRight(line, "\t ") + keylen := strings.IndexAny(line, "\t =") + if keylen < 0 { + keylen = len(line) + } + + variable := line[:keylen] + + value := strings.TrimLeft(line[keylen:], "\t ") + if strings.HasPrefix(value, "=") { + value = strings.TrimLeft(value[1:], "\t ") + } + + return variable, value +} + +func readConfigFile(fname string) (map[string][]string, error) { + config_tree := make(map[string][]string) + + fp, err := os.Open(fname) + if err != nil { + return nil, Error{File: fname, Err: err} + } + + buffer := bufio.NewScanner(fp) + + lineno := 0 + ignore := false + for buffer.Scan() { + line := buffer.Text() + + lineno++ + + if len(line) == 0 || line[0] == '#' { + continue + } + + if ignore { + if strings.HasPrefix(line, "-----END") { + ignore = false + } + + continue + } + + if strings.HasPrefix(line, "-----BEGIN") { + ignore = true + continue + + } + + variable, value := parseConfigLine(line) + if len(value) == 0 { + err = fmt.Errorf("No value for variable: %s", variable) + return nil, Error{File: fname, Line: lineno, Err: err} + } + variable = strings.ToLower(variable) + config_tree[variable] = append(config_tree[variable], value) + } + + err = buffer.Err() + if err != nil { + return nil, Error{File: fname, Err: err} + } + return config_tree, nil +} + +// Returns a list of public addresses for a host-config in Go +// "net.Dial" format. +func getAddresses(cfg map[string][]string) []string { + var result []string + + for _, node := range cfg["address"] { + var port string + space := strings.IndexByte(node, ' ') + if space < 0 { + if ports, portsOk := cfg["port"]; portsOk { + port = ports[0] + } else { + port = "655" + } + } else { + port = node[space+1:] + node = node[:space] + } + + if isIPv6(node) { + result = append(result, fmt.Sprintf("[%s]:%s", node, port)) + } else { + result = append(result, fmt.Sprintf("%s:%s", node, port)) + } + } + + return result +} + +func isIPv6(node string) bool { + ip := net.ParseIP(node) + return ip != nil && ip.To4() == nil +} -- cgit v1.2.3-54-g00ecf