Skip to content

Instantly share code, notes, and snippets.

@thypon
Created December 14, 2014 15:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thypon/7504ee8501bf2cfeaeb6 to your computer and use it in GitHub Desktop.
Save thypon/7504ee8501bf2cfeaeb6 to your computer and use it in GitHub Desktop.
Logs Users that connects via DHCP
package main
import (
"flag"
"log"
"net"
"time"
"sync"
"errors"
"github.com/krolaw/dhcp4"
"github.com/tatsushid/go-fastping"
)
var (
interval = 60
retries = 10
)
type Logger struct {
lc *LiveChecker
}
func NewLogger() *Logger {
lc := NewLiveChecker(time.Duration(interval))
go lc.Run()
return &Logger{lc}
}
func (l *Logger) ServeDHCP(p dhcp4.Packet, msgType dhcp4.MessageType, options dhcp4.Options) dhcp4.Packet {
switch msgType {
case dhcp4.Request:
mac := p.CHAddr()
ip := net.IP(p.ParseOptions()[dhcp4.OptionRequestedIPAddress])
log.Println("[Request] with MAC", mac, "and IP", ip)
l.lc.Add(mac, ip)
}
return nil
}
type ClientsMap struct {
mut sync.RWMutex
m map[string]net.IP
}
func NewClientsMap() *ClientsMap {
return &ClientsMap{m: make(map[string]net.IP)}
}
func (cm *ClientsMap) Add(mac string, ip net.IP) {
cm.mut.RLock()
defer cm.mut.RUnlock()
cm.m[mac] = ip
}
func (cm *ClientsMap) Keys() []string {
cm.mut.RLock()
defer cm.mut.RUnlock()
keys := make([]string, 0, len(cm.m))
for k := range cm.m {
keys = append(keys, k)
}
return keys
}
func (cm *ClientsMap) Get(mac string) net.IP {
cm.mut.RLock()
defer cm.mut.RUnlock()
return cm.m[mac]
}
func (cm *ClientsMap) Delete(mac string) {
cm.mut.RLock()
defer cm.mut.RUnlock()
delete(cm.m, mac)
}
func (l *LiveChecker) Add(mac net.HardwareAddr, ip net.IP) {
l.clients.Add(mac.String(), ip)
}
type LiveChecker struct {
clients *ClientsMap
freq time.Duration
}
func NewLiveChecker(freq time.Duration) *LiveChecker {
return &LiveChecker{
NewClientsMap(),
freq * time.Second}
}
func (l *LiveChecker) Run() {
for range time.Tick(l.freq) {
keys := l.clients.Keys()
cLen := len(keys)
inv := l.freq / time.Duration(cLen)
for _, k := range keys {
go func() {
ip := l.clients.Get(k)
err := ping(ip, inv)
if err != nil {
log.Println(err)
l.clients.Delete(k)
log.Println(ip, "Dead with MAC", k)
} else {
log.Println(ip, "Alive with MAC", k)
}
} ()
time.Sleep(inv)
}
}
}
func ping(ip net.IP, inv time.Duration) error {
p := fastping.NewPinger()
p.AddIP(ip.String())
recv := false
p.OnRecv = func(addr *net.IPAddr, rtt time.Duration) {
recv = true
}
for i := 0; i < retries && !recv; i++ {
go p.Run()
time.Sleep(inv / time.Duration(retries))
}
if !recv {
return errors.New("No Response")
}
return nil
}
func main() {
flag.Parse()
c := NewClientsMap()
c.Add("ciao", nil)
log.Println("DHCP Listen on", flag.Arg(0))
log.Fatal(dhcp4.ListenAndServeIf(flag.Arg(0), NewLogger()))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment