v0.0.2 next step: acutally try to nsupdate
upto the point where DNS update is next. start displaying real AAAA & naming buttons add RFC 2136 defining nsupdate. Vixie et al in 1997 Personal thansk to Paul for meeting with me some years back ready to pull DNS records starting a checkDNS() function dampen output. actually track IPs poll every 2 seconds (netlink is not the right thing here) ready to start looking for changes screw everything about logging. I hate log.whatthefuck*(){} Do you know what I don't care about? log() You shouldn't care either. Ignore it until you need it that is what logging is for. building something that works. So, here you go. a damn log() function in one place Also, because I'm annoyed today sleep() and exit() Because, when I want you to sleep or exit, I don't want to go to the top of a file and declare stupid shit related to nanoseconds or add "import os.Exit" or whatever the hell stop wasting my time. life is short. if he sit tunnelbroker down add IsRealIP() and IsIPv6() need a netlink function to trigger on changes (nope) put the gui plugin's in the debian package for now set the window title build a .deb package Signed-off-by: Jeff Carr <jcarr@wit.com>
This commit is contained in:
parent
3959b6c328
commit
7ad38cdf6c
|
@ -1 +1,3 @@
|
|||
control-panel-dns
|
||||
/files/*
|
||||
/*.deb
|
||||
|
|
47
Makefile
47
Makefile
|
@ -1,16 +1,59 @@
|
|||
run: build
|
||||
./control-panel-dns
|
||||
|
||||
verbose: build
|
||||
./control-panel-dns --verbose --verbose-net --gui-debug --toolkit-debug
|
||||
|
||||
dns: build
|
||||
./control-panel-dns --verbose-dns
|
||||
|
||||
build-release:
|
||||
reset
|
||||
go get -v -u -x .
|
||||
go build
|
||||
|
||||
build:
|
||||
reset
|
||||
GO111MODULE="off" go get -v -x .
|
||||
GO111MODULE="off" go build
|
||||
GO111MODULE="off" go build -v
|
||||
|
||||
test:
|
||||
GO111MODULE="off" go test -v
|
||||
|
||||
update:
|
||||
GO111MODULE="off" go get -v -u -x .
|
||||
|
||||
clean:
|
||||
rm control-panel-dns
|
||||
-rm control-panel-dns
|
||||
-rm -rf files/
|
||||
-rm *.deb
|
||||
|
||||
deb:
|
||||
cd debian && make
|
||||
-wit mirrors
|
||||
|
||||
netlink:
|
||||
GO111MODULE="off" go get -v -u github.com/vishvananda/netlink
|
||||
|
||||
|
||||
####### MODULE STUFF DOWN HERE
|
||||
#
|
||||
# What again is the 'right' way to do this?
|
||||
# It seems like it changes from year to year. This is better than 'vendor/' (that was a terrible hack)
|
||||
# maybe it's settled down finally. Use GO111MODULE="off" when you are developing. (?)
|
||||
# When you are ready to release, version this and all the packages correctly. (?)
|
||||
#
|
||||
# At least, that is what I'm going to try to do as of Feb 18 2023.
|
||||
#
|
||||
|
||||
|
||||
build-with-custom-go.mod:
|
||||
go build -modfile=local.go.mod ./...
|
||||
|
||||
# module <yourname>
|
||||
# go 1.18
|
||||
# require (
|
||||
# github.com/versent/saml2aws/v2 v2.35.0
|
||||
# )
|
||||
# replace github.com/versent/saml2aws/v2 v2.35.0 => github.com/marcottedan/saml2aws/v2 master
|
||||
# replace github.com/versent/saml2aws/v2 => /Users/dmarcotte/git/saml2aws/
|
||||
|
|
|
@ -9,6 +9,13 @@ Goals:
|
|||
* Run as a daemon
|
||||
* When run in GUI, add status via systray
|
||||
|
||||
# Rational
|
||||
|
||||
With the advent of IPv6, it is finally possible again to have real hostnames for
|
||||
your machines, desktops, laptops, vm's, etc. This control panel will poll for
|
||||
changes, find out what the DNS entries are, then, if they are not correct, attempt
|
||||
to update the DNS server.
|
||||
|
||||
## References
|
||||
|
||||
Useful links and other
|
||||
|
|
4
args.go
4
args.go
|
@ -6,8 +6,10 @@ import (
|
|||
)
|
||||
|
||||
type LogOptions struct {
|
||||
LogFile string
|
||||
LogFile string `help:"write all output to a file"`
|
||||
Verbose bool
|
||||
VerboseNet bool `arg:"--verbose-net" help:"debug network settings"`
|
||||
VerboseDNS bool `arg:"--verbose-dns" help:"debug dns settings"`
|
||||
// GuiDebug bool `help:"open up the wit/gui Debugging Window"`
|
||||
// GuiDemo bool `help:"open the wit/gui Demo Window"`
|
||||
User string `arg:"env:USER"`
|
||||
|
|
|
@ -20,6 +20,9 @@ clean:
|
|||
|
||||
extract:
|
||||
mkdir -p ../files/usr/bin
|
||||
mkdir -p ../files/usr/lib/control-panel-dns/
|
||||
-cp ~/go/src/git.wit.org/wit/gui/toolkit/*.so ../files/usr/lib/control-panel-dns/
|
||||
cp ../README.md ../files/usr/lib/control-panel-dns/
|
||||
cp ../control-panel-dns ../files/usr/bin/
|
||||
|
||||
# makes the DEBIAN/ directory
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
Source: go-wit-gui
|
||||
Source: control-panel-dns
|
||||
Build-Depends: golang
|
||||
Package: go-wit-gui
|
||||
Package: control-panel-dns
|
||||
Maintainer: Jeff Carr <jcarr@wit.com>
|
||||
Architecture: amd64
|
||||
Depends:
|
||||
Recommends: libgtk-3-0
|
||||
Description: a abstraction layer for Go visual elements (GTK, QT, etc)
|
||||
Package gui implements a abstraction layer for Go visual elements.
|
||||
Recommends: libgtk-3-0, ddclient, ddupdate
|
||||
Description: a control panel for DNS and IPv6 settings
|
||||
Goals: show the settings, validate & update DNS
|
||||
|
|
65
dns.go
65
dns.go
|
@ -5,28 +5,10 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
// "os"
|
||||
// "os/exec"
|
||||
"log"
|
||||
"net"
|
||||
// "git.wit.org/wit/gui"
|
||||
// "github.com/davecgh/go-spew/spew"
|
||||
)
|
||||
|
||||
type IPtype struct {
|
||||
// IP string
|
||||
IPv4 bool
|
||||
IPv6 bool
|
||||
LinkLocal bool
|
||||
}
|
||||
|
||||
type Host struct {
|
||||
Name string
|
||||
domainname string
|
||||
hostname string
|
||||
fqdn string
|
||||
ips map[string]*IPtype
|
||||
}
|
||||
var dnsTTL int = 3600; // Recheck DNS is working every TTL (in seconds)
|
||||
|
||||
/*
|
||||
Check a bunch of things. If they don't work right, then things are not correctly configured
|
||||
|
@ -43,9 +25,50 @@ func (h *Host) verifyETC() bool {
|
|||
func (h *Host) updateIPs(host string) {
|
||||
ips, err := net.LookupIP(host)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
exit(err)
|
||||
}
|
||||
for _, ip := range ips {
|
||||
log.Println(host, ip)
|
||||
log(host, ip)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Host) setIPv4(ipv4s map[string]*IPtype) {
|
||||
for ip, t := range ipv4s {
|
||||
log("IPv4", ip, t)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Host) checkDNS() {
|
||||
var ip4 bool = false
|
||||
var ip6 bool = false
|
||||
|
||||
for s, t := range h.ipmap {
|
||||
i := t.iface
|
||||
ipt := "IPv4"
|
||||
if (t.ipv6) {
|
||||
ipt = "IPv6"
|
||||
}
|
||||
if (! t.IsReal()) {
|
||||
log(args.VerboseDNS, "\tIP is not Real", ipt, i.Index, i.Name, s)
|
||||
continue
|
||||
}
|
||||
|
||||
log(args.VerboseDNS, "\tIP is Real ", ipt, i.Index, i.Name, s)
|
||||
if (t.ipv6) {
|
||||
ip6 = true
|
||||
} else {
|
||||
ip4 = true
|
||||
}
|
||||
}
|
||||
|
||||
if (ip4 == true) {
|
||||
log(args.VerboseDNS, "IPv4 should work. Wow. You actually have a real IPv4 address")
|
||||
} else {
|
||||
log(args.VerboseDNS, "IPv4 is broken. (be nice and setup ipv4-only.wit.com)")
|
||||
}
|
||||
if (ip6 == true) {
|
||||
log(args.VerboseDNS, "IPv6 should be working. Need to test it here.")
|
||||
} else {
|
||||
log(args.VerboseDNS, "IPv6 is broken. Need to fix it here.")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
package main
|
||||
|
||||
/*
|
||||
https://pkg.go.dev/github.com/miekg/dns#section-readme
|
||||
|
||||
DYNAMIC UPDATES
|
||||
|
||||
Dynamic updates reuses the DNS message format, but renames three of the sections. Question is Zone, Answer is Prerequisite, Authority is Update, only the Additional is not renamed. See RFC 2136 for the gory details.
|
||||
|
||||
You can set a rather complex set of rules for the existence of absence of certain resource records or names in a zone to specify if resource records should be added or removed. The table from RFC 2136 supplemented with the Go DNS function shows which functions exist to specify the prerequisites.
|
||||
|
||||
3.2.4 - Table Of Metavalues Used In Prerequisite Section
|
||||
|
||||
CLASS TYPE RDATA Meaning Function
|
||||
--------------------------------------------------------------
|
||||
ANY ANY empty Name is in use dns.NameUsed
|
||||
ANY rrset empty RRset exists (value indep) dns.RRsetUsed
|
||||
NONE ANY empty Name is not in use dns.NameNotUsed
|
||||
NONE rrset empty RRset does not exist dns.RRsetNotUsed
|
||||
zone rrset rr RRset exists (value dep) dns.Used
|
||||
|
||||
The prerequisite section can also be left empty. If you have decided on the prerequisites you can tell what RRs should be added or deleted. The next table shows the options you have and what functions to call.
|
||||
|
||||
3.4.2.6 - Table Of Metavalues Used In Update Section
|
||||
|
||||
CLASS TYPE RDATA Meaning Function
|
||||
---------------------------------------------------------------
|
||||
ANY ANY empty Delete all RRsets from name dns.RemoveName
|
||||
ANY rrset empty Delete an RRset dns.RemoveRRset
|
||||
NONE rrset rr Delete an RR from RRset dns.Remove
|
||||
zone rrset rr Add to an RRset dns.Insert
|
||||
*/
|
|
@ -0,0 +1,76 @@
|
|||
package main
|
||||
|
||||
// Watches for changes to a directory. Works cross-platform
|
||||
|
||||
import (
|
||||
"github.com/fsnotify/fsnotify"
|
||||
)
|
||||
|
||||
// This would be a really dumb way to watch for new network interfaces
|
||||
// since it then watches a linux only directory /sys/class/net for changes
|
||||
|
||||
func watchSysClassNet() {
|
||||
// Create new watcher.
|
||||
watcher, err := fsnotify.NewWatcher()
|
||||
if err != nil {
|
||||
exit(err)
|
||||
}
|
||||
defer watcher.Close()
|
||||
|
||||
// Start listening for events.
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case event, ok := <-watcher.Events:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
log("event:", event)
|
||||
if event.Has(fsnotify.Write) {
|
||||
log("modified file:", event.Name)
|
||||
}
|
||||
case err, ok := <-watcher.Errors:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
log("error:", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// Add a path.
|
||||
err = watcher.Add("/tmp")
|
||||
if err != nil {
|
||||
exit(err)
|
||||
}
|
||||
|
||||
// Block main goroutine forever.
|
||||
<-make(chan struct{})
|
||||
}
|
||||
|
||||
func fsnotifyNetworkInterfaceChanges() error {
|
||||
watcher, err := fsnotify.NewWatcher()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer watcher.Close()
|
||||
|
||||
// Watch for network interface changes
|
||||
err = watcher.Add("/sys/class/net")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for {
|
||||
select {
|
||||
case event := <-watcher.Events:
|
||||
log("fsnotifyNetworkInterfaceChanges() event =", event)
|
||||
if event.Op&fsnotify.Create == fsnotify.Create {
|
||||
// Do something on network interface creation
|
||||
}
|
||||
case err := <-watcher.Errors:
|
||||
log("fsnotifyNetworkInterfaceChanges() event err =", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
59
gui.go
59
gui.go
|
@ -4,7 +4,6 @@ package main
|
|||
import (
|
||||
"os"
|
||||
"os/user"
|
||||
"log"
|
||||
"net"
|
||||
"git.wit.org/wit/gui"
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
|
@ -13,14 +12,14 @@ import (
|
|||
// This initializes the first window
|
||||
func initGUI() {
|
||||
var w *gui.Node
|
||||
gui.Config.Title = "Hello World golang wit/gui Window"
|
||||
gui.Config.Title = "DNS and IPv6 Control Panel"
|
||||
gui.Config.Width = 640
|
||||
gui.Config.Height = 480
|
||||
gui.Config.Exit = myDefaultExit
|
||||
|
||||
w = gui.NewWindow()
|
||||
w.Dump()
|
||||
addDemoTab(w, "A Simple Tab Demo")
|
||||
addDNSTab(w, "DNS")
|
||||
|
||||
// TODO: add these back
|
||||
if (args.GuiDemo) {
|
||||
|
@ -32,16 +31,14 @@ func initGUI() {
|
|||
}
|
||||
}
|
||||
|
||||
func addDemoTab(window *gui.Node, title string) {
|
||||
func addDNSTab(window *gui.Node, title string) {
|
||||
var newNode, g, g2, tb *gui.Node
|
||||
var err error
|
||||
var name string
|
||||
|
||||
newNode = window.NewTab(title)
|
||||
log.Println("addDemoTab() newNode.Dump")
|
||||
log("addDemoTab() newNode.Dump")
|
||||
newNode.Dump()
|
||||
|
||||
g = newNode.NewGroup("group 1")
|
||||
g = newNode.NewGroup("junk")
|
||||
dd := g.NewDropdown("demoCombo2")
|
||||
dd.AddDropdownName("more 1")
|
||||
dd.AddDropdownName("more 2")
|
||||
|
@ -49,27 +46,49 @@ func addDemoTab(window *gui.Node, title string) {
|
|||
dd.OnChanged = func(*gui.Node) {
|
||||
s := dd.GetText()
|
||||
tb.SetText("hello world " + args.User + "\n" + s)
|
||||
log("text =", s)
|
||||
}
|
||||
g.NewLabel("UID =")
|
||||
g.NewButton("hello", func () {
|
||||
log("world")
|
||||
})
|
||||
|
||||
g2 = newNode.NewGroup("group 2")
|
||||
|
||||
g2 = newNode.NewGroup("Real Stuff")
|
||||
tb = g2.NewTextbox("tb")
|
||||
log.Println("tb =", tb.GetText())
|
||||
log("tb =", tb.GetText())
|
||||
tb.OnChanged = func(*gui.Node) {
|
||||
s := tb.GetText()
|
||||
log.Println("text =", s)
|
||||
log("text =", s)
|
||||
}
|
||||
g2.NewButton("hello", func () {
|
||||
log.Println("world")
|
||||
scanInterfaces()
|
||||
g2.NewButton("Network Interfaces", func () {
|
||||
for i, t := range me.ifmap {
|
||||
log("name =", t.iface.Name)
|
||||
log("int =", i, "name =", t.name, t.iface)
|
||||
dd.AddDropdownName(t.iface.Name)
|
||||
}
|
||||
})
|
||||
g2.NewButton("os.Hostname()", func () {
|
||||
name, err = os.Hostname()
|
||||
log.Println("name =", name, err)
|
||||
g2.NewButton("Hostname", func () {
|
||||
getHostname()
|
||||
g.NewLabel("FQDN = " + me.fqdn)
|
||||
})
|
||||
g2.NewButton("Actual AAAA", func () {
|
||||
var aaaa []string
|
||||
aaaa = realAAAA()
|
||||
for _, s := range aaaa {
|
||||
g.NewLabel("my actual AAAA = " + s)
|
||||
}
|
||||
})
|
||||
g2.NewButton("checkDNS()", func () {
|
||||
checkDNS()
|
||||
})
|
||||
g2.NewButton("os.User()", func () {
|
||||
user, _ := user.Current()
|
||||
spew.Dump(user)
|
||||
log.Println("os.Getuid =", os.Getuid())
|
||||
log("os.Getuid =", os.Getuid())
|
||||
})
|
||||
g2.NewButton("Example_listLink()", func () {
|
||||
Example_listLink()
|
||||
})
|
||||
g2.NewButton("Escalate()", func () {
|
||||
Escalate()
|
||||
|
@ -79,7 +98,7 @@ func addDemoTab(window *gui.Node, title string) {
|
|||
if err != nil {
|
||||
return
|
||||
}
|
||||
log.Println("host =", host)
|
||||
log("host =", host)
|
||||
})
|
||||
g2.NewButton("DumpPublicDNSZone(apple.com)", func () {
|
||||
DumpPublicDNSZone("apple.com")
|
||||
|
@ -88,6 +107,6 @@ func addDemoTab(window *gui.Node, title string) {
|
|||
}
|
||||
|
||||
func myDefaultExit(n *gui.Node) {
|
||||
log.Println("You can Do exit() things here")
|
||||
log("You can Do exit() things here")
|
||||
os.Exit(0)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
#!/bin/bash -x
|
||||
|
||||
## Tunnel ID: 818143
|
||||
# Creation Date:Feb 12, 2023
|
||||
# Description:
|
||||
# IPv6 Tunnel Endpoints
|
||||
# Server IPv4 Address:184.105.253.14
|
||||
# Server IPv6 Address:2001:470:1f10:2a::1/64
|
||||
# Client IPv4 Address:74.87.91.117
|
||||
# Client IPv6 Address:2001:470:1f10:2a::2/64
|
||||
# Routed IPv6 Prefixes
|
||||
# Routed /64:2001:470:1f11:2a::/64
|
||||
# Routed /48:Assign /48
|
||||
# DNS Resolvers
|
||||
# Anycast IPv6 Caching Nameserver:2001:470:20::2
|
||||
# Anycast IPv4 Caching Nameserver:74.82.42.42
|
||||
# DNS over HTTPS / DNS over TLS:ordns.he.net
|
||||
# rDNS DelegationsEdit
|
||||
# rDNS Delegated NS1:
|
||||
# rDNS Delegated NS2:
|
||||
# rDNS Delegated NS3:
|
||||
# rDNS Delegated NS4:
|
||||
# rDNS Delegated NS5:
|
||||
|
||||
# ifconfig sit0 up
|
||||
# ifconfig sit0 inet6 tunnel ::184.105.253.14
|
||||
# ifconfig sit1 up
|
||||
# ifconfig sit1 inet6 add 2001:470:1f10:2a::2/64
|
||||
# route -A inet6 add ::/0 dev sit1
|
||||
|
||||
if [ "$1" = "down" ]; then
|
||||
ip tunnel del he-ipv6
|
||||
rmmod sit
|
||||
exit
|
||||
fi
|
||||
|
||||
if [ "$1" = "ping" ]; then
|
||||
ping -c 3 2001:470:1f10:13d::1
|
||||
exit
|
||||
fi
|
||||
|
||||
modprobe ipv6
|
||||
ip tunnel add he-ipv6 mode sit remote 184.105.253.14 local 40.132.180.131 ttl 255
|
||||
ip link set he-ipv6 up
|
||||
ip addr add 2001:470:1f10:13d::2/64 dev he-ipv6
|
||||
ip route add ::/0 dev he-ipv6
|
||||
ip -f inet6 addr
|
||||
ifconfig he-ipv6 mtu 1460
|
||||
|
||||
|
||||
# old attempt from the something or pabtz hotel
|
||||
# modprobe ipv6
|
||||
# ip tunnel add he-ipv6 mode sit remote 184.105.253.14 local 74.87.91.117 ttl 255
|
||||
# ip link set he-ipv6 up
|
||||
# ip addr add 2001:470:1f10:2a::2/64 dev he-ipv6
|
||||
# ip route add ::/0 dev he-ipv6
|
||||
# ip -f inet6 addr
|
|
@ -0,0 +1,45 @@
|
|||
// inspired from:
|
||||
// https://github.com/mactsouk/opensource.com.git
|
||||
// and
|
||||
// https://coderwall.com/p/wohavg/creating-a-simple-tcp-server-in-go
|
||||
|
||||
package main
|
||||
|
||||
// import "net"
|
||||
|
||||
// will try to get this hosts FQDN
|
||||
import "github.com/Showmax/go-fqdn"
|
||||
|
||||
// this is the king of dns libraries
|
||||
import "github.com/miekg/dns"
|
||||
|
||||
// dnssec IPv6 socket library
|
||||
import "git.wit.org/jcarr/dnssecsocket"
|
||||
|
||||
func getHostname() {
|
||||
var err error
|
||||
me.fqdn, err = fqdn.FqdnHostname()
|
||||
if (err != nil) {
|
||||
log("FQDN hostname error =", err)
|
||||
exit()
|
||||
return
|
||||
}
|
||||
log("FQDN hostname is", me.fqdn)
|
||||
|
||||
var aaaa []string
|
||||
aaaa = getAAAA(me.fqdn)
|
||||
log("AAAA =", aaaa)
|
||||
}
|
||||
|
||||
func getAAAA(s string) []string {
|
||||
// lookup the IP address from DNS
|
||||
dnsRR := dnssecsocket.Dnstrace(s, "AAAA")
|
||||
log(args.VerboseDNS, SPEW, dnsRR)
|
||||
if (dnsRR == nil) {
|
||||
return nil
|
||||
}
|
||||
ipaddr1 := dns.Field(dnsRR, 1)
|
||||
ipaddr2 := dns.Field(dnsRR, 2)
|
||||
log("ipaddr", ipaddr1, ipaddr2)
|
||||
return []string{ipaddr1, ipaddr2}
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
// I like things to be easy. Why can't the standard language be like this?
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
golog "log"
|
||||
"time"
|
||||
"reflect"
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
// "net"
|
||||
)
|
||||
|
||||
var LOGOFF bool = false // turn this off, all logging stops
|
||||
var WARN bool
|
||||
var INFO bool
|
||||
|
||||
type spewt struct {
|
||||
a bool
|
||||
}
|
||||
|
||||
var SPEW spewt
|
||||
|
||||
|
||||
/*
|
||||
sleep() # you know what this does? sleeps for 1 second. yep. dump. easy.
|
||||
sleep(.1) # you know what this does? yes, it sleeps for 1/10th of a second
|
||||
*/
|
||||
func sleep(a ...any) {
|
||||
if (a == nil) {
|
||||
time.Sleep(time.Second)
|
||||
return
|
||||
}
|
||||
|
||||
log(args.Verbose, "sleep", a[0])
|
||||
|
||||
switch a[0].(type) {
|
||||
case int:
|
||||
time.Sleep(time.Duration(a[0].(int)) * time.Second)
|
||||
case float64:
|
||||
time.Sleep(time.Duration(a[0].(float64) * 1000) * time.Millisecond)
|
||||
default:
|
||||
log("sleep a[0], type = ", a[0], reflect.TypeOf(a[0]))
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
exit() # yep. exits. I guess everything must be fine
|
||||
exit(3) # I guess 3 it is then
|
||||
exit("dont like apples") # ok. I'll make a note of that
|
||||
*/
|
||||
func exit(a ...any) {
|
||||
log("exit", a)
|
||||
//if (a) {
|
||||
// os.Exit(a)
|
||||
//}
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
/*
|
||||
I've spent, am spending, too much time thinking about 'logging'. 'log', 'logrus', 'zap', whatever.
|
||||
I'm not twitter. i don't give a fuck about how many nanoseconds it takes to log. Anyway, this
|
||||
implementation is probably faster than all of those because you just set one bool to FALSE
|
||||
and it all stops.
|
||||
Sometimes I need to capture to stdout, sometimes stdout can't
|
||||
work because it doesn't exist for the user. This whole thing is a PITA. Then it's spread
|
||||
over 8 million references in every .go file. I'm tapping out and putting
|
||||
it in one place. here it is. Also, this makes having debug levels really fucking easy.
|
||||
You can define whatever level of logging you want from anywhere (command line) etc.
|
||||
|
||||
log() # doesn't do anything
|
||||
log(stuff) # sends it to whatever log you define in a single place. here is the place
|
||||
*/
|
||||
|
||||
func log(a ...any) {
|
||||
if (LOGOFF) {
|
||||
return
|
||||
}
|
||||
|
||||
if (a == nil) {
|
||||
return
|
||||
}
|
||||
var blah bool
|
||||
if (reflect.TypeOf(a[0]) == reflect.TypeOf(blah)) {
|
||||
// golog.Println("\t a[0] = bool")
|
||||
if (a[0] == false) {
|
||||
return
|
||||
}
|
||||
a = a[1:]
|
||||
}
|
||||
|
||||
if (reflect.TypeOf(a[0]) == reflect.TypeOf(SPEW)) {
|
||||
a = a[1:]
|
||||
spew.Dump(a)
|
||||
return
|
||||
}
|
||||
|
||||
golog.Println(a...)
|
||||
// golog.Println("\t a[0] =", a[0])
|
||||
// for argNum, arg := range a {
|
||||
// golog.Println("\t", argNum, arg)
|
||||
// }
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package main
|
||||
|
||||
/*
|
||||
import "log"
|
||||
import "github.com/miekg/dns"
|
||||
|
||||
import "git.wit.org/jcarr/dnssecsocket"
|
||||
|
||||
import "github.com/davecgh/go-spew/spew"
|
||||
// import "github.com/Showmax/go-fqdn"
|
||||
|
||||
func lookupAAAA(hostname string) string {
|
||||
// lookup the IP address from DNS
|
||||
dnsRR := dnssecsocket.Dnstrace(hostname, "AAAA")
|
||||
spew.Dump(dnsRR)
|
||||
if (dnsRR == nil) {
|
||||
return "BROKEN"
|
||||
}
|
||||
ipaddr := dns.Field(dnsRR, 1)
|
||||
log.Println("ipaddr", ipaddr)
|
||||
return ipaddr
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
func main() {
|
||||
hostname := "check.lab.wit.org"
|
||||
// 2604:bbc0:2:248:5054:f0ff:fe00:156
|
||||
|
||||
lookupAAAA(hostname)
|
||||
}
|
||||
*/
|
101
main.go
101
main.go
|
@ -1,90 +1,49 @@
|
|||
// This creates a simple hello world window
|
||||
// This is a control panel for DNS
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net"
|
||||
"github.com/fsnotify/fsnotify"
|
||||
"runtime"
|
||||
// "net"
|
||||
"git.wit.org/wit/gui"
|
||||
arg "github.com/alexflint/go-arg"
|
||||
)
|
||||
|
||||
var me Host
|
||||
|
||||
func main() {
|
||||
arg.MustParse(&args)
|
||||
// fmt.Println(args.Foo, args.Bar, args.User)
|
||||
log.Println("Toolkit = ", args.Toolkit)
|
||||
|
||||
me.ips = make(map[string]*IPtype)
|
||||
// initialize the maps to track IP addresses and network interfaces
|
||||
me.ipmap = make(map[string]*IPtype)
|
||||
me.ifmap = make(map[int]*IFtype)
|
||||
|
||||
go checkNetworkChanges()
|
||||
|
||||
log()
|
||||
log(true, "this is true")
|
||||
log(false, "this is false")
|
||||
sleep(.4)
|
||||
sleep(.3)
|
||||
sleep(.2)
|
||||
sleep("done scanning net")
|
||||
// exit("done scanning net")
|
||||
|
||||
// Example_listLink()
|
||||
// exit()
|
||||
|
||||
log("Toolkit = ", args.Toolkit)
|
||||
// gui.InitPlugins([]string{"andlabs"})
|
||||
|
||||
scanInterfaces()
|
||||
watchNetworkInterfaces()
|
||||
go inotifyNetworkInterfaceChanges()
|
||||
gui.Main(initGUI)
|
||||
}
|
||||
|
||||
func watchNetworkInterfaces() {
|
||||
// Get list of network interfaces
|
||||
interfaces, _ := net.Interfaces()
|
||||
|
||||
// Set up a notification channel
|
||||
notification := make(chan net.Interface)
|
||||
|
||||
// Start goroutine to watch for changes
|
||||
go func() {
|
||||
for {
|
||||
// Check for changes in each interface
|
||||
for _, i := range interfaces {
|
||||
if status := i.Flags & net.FlagUp; status != 0 {
|
||||
notification <- i
|
||||
log.Println("something on i =", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func inotifyNetworkInterfaceChanges() error {
|
||||
watcher, err := fsnotify.NewWatcher()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer watcher.Close()
|
||||
|
||||
// Watch for network interface changes
|
||||
err = watcher.Add("/sys/class/net")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
/*
|
||||
Poll for changes to the networking settings
|
||||
*/
|
||||
func checkNetworkChanges() {
|
||||
for {
|
||||
select {
|
||||
case event := <-watcher.Events:
|
||||
log.Println("inotifyNetworkInterfaceChanges() event =", event)
|
||||
if event.Op&fsnotify.Create == fsnotify.Create {
|
||||
// Do something on network interface creation
|
||||
}
|
||||
case err := <-watcher.Errors:
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func scanInterfaces() {
|
||||
ifaces, _ := net.Interfaces()
|
||||
for _, i := range ifaces {
|
||||
log.Println(i)
|
||||
addrs, _ := i.Addrs()
|
||||
for _, addr := range addrs {
|
||||
log.Println("\taddr =", addr)
|
||||
switch v := addr.(type) {
|
||||
case *net.IPNet:
|
||||
log.Println("\t\taddr.(type) = *net.IPNet")
|
||||
default:
|
||||
log.Println("\t\taddr.(type) =", v)
|
||||
}
|
||||
sleep(2)
|
||||
if (runtime.GOOS == "linux") {
|
||||
scanInterfaces()
|
||||
} else {
|
||||
log("Windows and MacOS don't work yet")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,223 @@
|
|||
// This creates a simple hello world window
|
||||
package main
|
||||
|
||||
import (
|
||||
"net"
|
||||
"strings"
|
||||
// "git.wit.org/wit/gui"
|
||||
)
|
||||
|
||||
var DEBUGNET bool = false
|
||||
|
||||
// this doesn't work
|
||||
/*
|
||||
func watchNetworkInterfaces() {
|
||||
// Get list of network interfaces
|
||||
interfaces, _ := net.Interfaces()
|
||||
|
||||
// Set up a notification channel
|
||||
notification := make(chan net.Interface)
|
||||
|
||||
log(DEBUGNET, "watchNet()")
|
||||
// Start goroutine to watch for changes
|
||||
go func() {
|
||||
log(DEBUGNET, "watchNet() func")
|
||||
for {
|
||||
log(DEBUGNET, "forever loop start")
|
||||
// Check for changes in each interface
|
||||
for _, i := range interfaces {
|
||||
log(DEBUGNET, "something on i =", i)
|
||||
if status := i.Flags & net.FlagUp; status != 0 {
|
||||
notification <- i
|
||||
log(DEBUGNET, "something on i =", i)
|
||||
}
|
||||
}
|
||||
log(DEBUGNET, "forever loop end")
|
||||
}
|
||||
}()
|
||||
}
|
||||
*/
|
||||
|
||||
func IsIPv6(address string) bool {
|
||||
return strings.Count(address, ":") >= 2
|
||||
}
|
||||
|
||||
func (t *IPtype) IsReal() bool {
|
||||
if (t.ip.IsPrivate() || t.ip.IsLoopback() || t.ip.IsLinkLocalUnicast()) {
|
||||
log(DEBUGNET, "\t\tIP is Real = false")
|
||||
return false
|
||||
} else {
|
||||
log(DEBUGNET, "\t\tIP is Real = true")
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
func IsReal(ip *net.IP) bool {
|
||||
if (ip.IsPrivate() || ip.IsLoopback() || ip.IsLinkLocalUnicast()) {
|
||||
log(DEBUGNET, "\t\tIP is Real = false")
|
||||
return false
|
||||
} else {
|
||||
log(DEBUGNET, "\t\tIP is Real = true")
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
func renameInterface(i *net.Interface) {
|
||||
/*
|
||||
/sbin/ip link set eth1 down
|
||||
/sbin/ip link set eth1 name eth123
|
||||
/sbin/ip link set eth123 up
|
||||
*/
|
||||
}
|
||||
|
||||
// Will figure out if an interface was just added
|
||||
func checkInterface(i net.Interface) {
|
||||
val, ok := me.ifmap[i.Index]
|
||||
if ! ok {
|
||||
log(i.Name, "is a new network interface. The linux kernel index =", i.Index)
|
||||
me.ifmap[i.Index] = new(IFtype)
|
||||
me.ifmap[i.Index].gone = false
|
||||
me.ifmap[i.Index].iface = &i
|
||||
me.ipchange = true
|
||||
return
|
||||
}
|
||||
me.ifmap[i.Index].gone = false
|
||||
log(args.VerboseNet, "me.ifmap[i] does exist. Need to compare everything.", i.Index, i.Name, val.iface.Index, val.iface.Name)
|
||||
if (val.iface.Name != i.Name) {
|
||||
log(val.iface.Name, "has changed to it's name to", i.Name)
|
||||
me.ifmap[i.Index].iface = &i
|
||||
me.ipchange = true
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func realAAAA() []string {
|
||||
var aaaa []string
|
||||
|
||||
for s, t := range me.ipmap {
|
||||
if (t.IsReal()) {
|
||||
if (t.ipv6) {
|
||||
aaaa = append(aaaa, s)
|
||||
}
|
||||
}
|
||||
}
|
||||
return aaaa
|
||||
}
|
||||
|
||||
func checkDNS() (map[string]*IPtype, map[string]*IPtype) {
|
||||
var ipv4s map[string]*IPtype
|
||||
var ipv6s map[string]*IPtype
|
||||
|
||||
ipv4s = make(map[string]*IPtype)
|
||||
ipv6s = make(map[string]*IPtype)
|
||||
|
||||
for s, t := range me.ipmap {
|
||||
i := t.iface
|
||||
ipt := "IPv4"
|
||||
if (t.ipv6) {
|
||||
ipt = "IPv6"
|
||||
}
|
||||
if (t.IsReal()) {
|
||||
log("\tIP is Real ", ipt, i.Index, i.Name, s)
|
||||
if (t.ipv6) {
|
||||
ipv6s[s] = t
|
||||
} else {
|
||||
ipv4s[s] = t
|
||||
}
|
||||
} else {
|
||||
log("\tIP is not Real", ipt, i.Index, i.Name, s)
|
||||
}
|
||||
}
|
||||
return ipv6s, ipv4s
|
||||
}
|
||||
|
||||
// Will figure out if an IP address is new
|
||||
func checkIP(ip *net.IPNet, i net.Interface) bool {
|
||||
log(args.VerboseNet, "\t\taddr.(type) = *net.IPNet")
|
||||
log(args.VerboseNet, "\t\taddr.(type) =", ip)
|
||||
var realip string
|
||||
realip = ip.IP.String()
|
||||
|
||||
val, ok := me.ipmap[realip]
|
||||
if ok {
|
||||
log(args.VerboseNet, val.ipnet.IP.String(), "is already a defined IP address")
|
||||
me.ipmap[realip].gone = false
|
||||
return false
|
||||
}
|
||||
|
||||
me.ipmap[realip] = new(IPtype)
|
||||
me.ipmap[realip].gone = false
|
||||
me.ipmap[realip].ipv4 = true
|
||||
me.ipmap[realip].ipnet = ip
|
||||
me.ipmap[realip].ip = ip.IP
|
||||
me.ipmap[realip].iface = &i
|
||||
t := "IPv4"
|
||||
if (IsIPv6(ip.String())) {
|
||||
me.ipmap[realip].ipv6 = true
|
||||
me.ipmap[realip].ipv4 = false
|
||||
t = "IPv6"
|
||||
} else {
|
||||
me.ipmap[realip].ipv6 = false
|
||||
me.ipmap[realip].ipv4 = true
|
||||
}
|
||||
if (IsReal(&ip.IP)) {
|
||||
log("\tIP is Real ", t, i.Index, i.Name, realip)
|
||||
} else {
|
||||
log("\tIP is not Real", t, i.Index, i.Name, realip)
|
||||
}
|
||||
log(args.VerboseNet, "\t\tIP is IsPrivate() =", ip.IP.IsPrivate())
|
||||
log(args.VerboseNet, "\t\tIP is IsLoopback() =", ip.IP.IsLoopback())
|
||||
log(args.VerboseNet, "\t\tIP is IsLinkLocalUnicast() =", ip.IP.IsLinkLocalUnicast())
|
||||
// log("HERE HERE", "realip =", realip, "me.ip[realip]=", me.ipmap[realip])
|
||||
return true
|
||||
}
|
||||
|
||||
func scanInterfaces() {
|
||||
me.ipchange = false
|
||||
ifaces, _ := net.Interfaces()
|
||||
// me.ifnew = ifaces
|
||||
log(DEBUGNET, SPEW, ifaces)
|
||||
for _, i := range ifaces {
|
||||
addrs, _ := i.Addrs()
|
||||
// log("range ifaces = ", i)
|
||||
checkInterface(i)
|
||||
log(args.VerboseNet, "*net.Interface.Name = ", i.Name, i.Index)
|
||||
log(args.VerboseNet, SPEW, i)
|
||||
log(DEBUGNET, SPEW, addrs)
|
||||
for _, addr := range addrs {
|
||||
log(DEBUGNET, "\taddr =", addr)
|
||||
log(DEBUGNET, SPEW, addrs)
|
||||
ips, _ := net.LookupIP(addr.String())
|
||||
log(DEBUGNET, "\tLookupIP(addr) =", ips)
|
||||
switch v := addr.(type) {
|
||||
case *net.IPNet:
|
||||
checkIP(v, i)
|
||||
// log("\t\tIP is () =", ip.())
|
||||
default:
|
||||
log(DEBUGNET, "\t\taddr.(type) = NO IDEA WHAT TO DO HERE v =", v)
|
||||
}
|
||||
}
|
||||
}
|
||||
deleteChanges()
|
||||
}
|
||||
|
||||
// delete network interfaces and ip addresses from the gui
|
||||
func deleteChanges() {
|
||||
for i, t := range me.ifmap {
|
||||
if (t.gone) {
|
||||
log("DELETE int =", i, "name =", t.name, t.iface)
|
||||
delete(me.ifmap, i)
|
||||
}
|
||||
t.gone = true
|
||||
}
|
||||
for s, t := range me.ipmap {
|
||||
if (t.gone) {
|
||||
log("DELETE name =", s, "IPv4 =", t.ipv4)
|
||||
log("DELETE name =", s, "IPv6 =", t.ipv6)
|
||||
log("DELETE name =", s, "iface =", t.iface)
|
||||
log("DELETE name =", s, "ip =", t.ip)
|
||||
delete(me.ipmap, s)
|
||||
}
|
||||
t.gone = true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
package main
|
||||
|
||||
// examples of what ifconfig does
|
||||
// example of AF_NETLINK change:
|
||||
// https://stackoverflow.com/questions/579783/how-to-detect-ip-address-change-programmatically-in-linux/2353441#2353441
|
||||
// from that page, a link to watch for any ip event:
|
||||
// https://github.com/angt/ipevent/blob/master/ipevent.c
|
||||
|
||||
// https://github.com/mdlayher/talks : Linux, Netlink, and Go in 7 minutes or less! (GopherCon 2018, lightning talk)
|
||||
|
||||
/*
|
||||
c example from ipevent.c :
|
||||
int fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
||||
|
||||
struct sockaddr_nl snl = {
|
||||
.nl_family = AF_NETLINK,
|
||||
.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR,
|
||||
};
|
||||
*/
|
||||
|
||||
/*
|
||||
import (
|
||||
// "os"
|
||||
// "os/exec"
|
||||
// "log"
|
||||
// "net"
|
||||
// "unix"
|
||||
"github.com/vishvananda/netlink"
|
||||
"github.com/jsimonetti/rtnetlink"
|
||||
// "git.wit.org/wit/gui"
|
||||
// "github.com/davecgh/go-spew/spew"
|
||||
)
|
||||
|
||||
// In golang, write a function to register with netlink to detect changes to any network interface Use tab indentation. Do not include example usage.
|
||||
|
||||
func registerNetlink() error {
|
||||
// Create netlink socket
|
||||
sock, err := netlink.Socket(rtnetlink.NETLINK_ROUTE, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Register for interface change events
|
||||
err = netlink.AddMembership(sock, netlink.RTNLGRP_LINK)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Close the socket
|
||||
defer sock.Close()
|
||||
// Handle incoming notifications
|
||||
for {
|
||||
msgs, _, err := sock.Receive()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, msg := range msgs {
|
||||
switch msg.Header.Type {
|
||||
case unix.RTM_NEWLINK:
|
||||
// Do something with new link
|
||||
case unix.RTM_DELLINK:
|
||||
// Do something with deleted link
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
*/
|
|
@ -0,0 +1,24 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/jsimonetti/rtnetlink"
|
||||
)
|
||||
|
||||
// List all interfaces
|
||||
func Example_listLink() {
|
||||
// Dial a connection to the rtnetlink socket
|
||||
conn, err := rtnetlink.Dial(nil)
|
||||
if err != nil {
|
||||
exit(err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
// Request a list of interfaces
|
||||
msg, err := conn.Link.List()
|
||||
if err != nil {
|
||||
log(err)
|
||||
}
|
||||
|
||||
log("%#v", msg)
|
||||
log(SPEW, msg)
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
// This creates a simple hello world window
|
||||
package main
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
|
||||
// It's probably a terrible idea to call this 'me'
|
||||
var me Host
|
||||
|
||||
type Host struct {
|
||||
hostname string // mirrors
|
||||
domainname string // kernel.org
|
||||
fqdn string // mirrors.kernel.org
|
||||
ipmap map[string]*IPtype // the current ip addresses
|
||||
ifmap map[int]*IFtype // the current interfaces
|
||||
ipchange bool // set to true if things change
|
||||
}
|
||||
|
||||
type IPtype struct {
|
||||
gone bool // used to track if the ip exists
|
||||
ipv6 bool // the future
|
||||
ipv4 bool // the past
|
||||
LinkLocal bool
|
||||
iface *net.Interface
|
||||
ip net.IP
|
||||
ipnet *net.IPNet
|
||||
}
|
||||
|
||||
type IFtype struct {
|
||||
gone bool // used to track if the interface exists
|
||||
name string // just a shortcut to the name. maybe this is dumb
|
||||
// up bool // could be used to track ifup/ifdown
|
||||
iface *net.Interface
|
||||
}
|
24
unix.go
24
unix.go
|
@ -7,7 +7,6 @@ package main
|
|||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"log"
|
||||
"net"
|
||||
// "git.wit.org/wit/gui"
|
||||
// "github.com/davecgh/go-spew/spew"
|
||||
|
@ -19,13 +18,13 @@ func CheckSuperuser() bool {
|
|||
|
||||
func Escalate() {
|
||||
if os.Getuid() != 0 {
|
||||
cmd := exec.Command("sudo", "./control-panel-dns")
|
||||
cmd := exec.Command("sudo", "./control-panel-dns") // TODO: get the actual path
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
exit(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -39,16 +38,29 @@ func DumpPublicDNSZone(zone string) {
|
|||
panic(err)
|
||||
}
|
||||
for _, entry := range entries {
|
||||
log.Println(entry)
|
||||
log(entry)
|
||||
}
|
||||
}
|
||||
|
||||
func dumpIPs(host string) {
|
||||
ips, err := net.LookupIP(host)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
exit(err)
|
||||
}
|
||||
for _, ip := range ips {
|
||||
log.Println(host, ip)
|
||||
log(host, ip)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
check if ddclient is installed, working, and/or configured
|
||||
https://github.com/ddclient/ddclient
|
||||
*/
|
||||
func ddclient() {
|
||||
}
|
||||
|
||||
/*
|
||||
check if ddupdate is installed, working, and/or configured
|
||||
*/
|
||||
func ddupdate() {
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue