100 lines
2.0 KiB
Go
100 lines
2.0 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"encoding/json"
|
||
|
"fmt"
|
||
|
"log"
|
||
|
"net/http"
|
||
|
"os"
|
||
|
"os/signal"
|
||
|
"path"
|
||
|
"strings"
|
||
|
"syscall"
|
||
|
|
||
|
"github.com/gin-gonic/gin"
|
||
|
"gopkg.in/fsnotify.v1"
|
||
|
)
|
||
|
|
||
|
func (app *App) loadAndWatchIPs(ipfile string) {
|
||
|
// First load of file if it exists
|
||
|
app.tryReloadIPList(ipfile)
|
||
|
|
||
|
// Register SIGHUP
|
||
|
c := make(chan os.Signal, 1)
|
||
|
signal.Notify(c, syscall.SIGHUP)
|
||
|
go func() {
|
||
|
for range c {
|
||
|
log.Println("SIGHUP received, reloading ip list...")
|
||
|
go app.tryReloadIPList(ipfile)
|
||
|
}
|
||
|
}()
|
||
|
|
||
|
// Watch the configuration file
|
||
|
if watcher, err := fsnotify.NewWatcher(); err != nil {
|
||
|
log.Fatal(err)
|
||
|
} else {
|
||
|
if err := watcher.Add(path.Dir(ipfile)); err != nil {
|
||
|
log.Fatal("Unable to watch: ", path.Dir(ipfile), ": ", err)
|
||
|
}
|
||
|
|
||
|
go func() {
|
||
|
defer watcher.Close()
|
||
|
for {
|
||
|
select {
|
||
|
case ev := <-watcher.Events:
|
||
|
if path.Base(ev.Name) == path.Base(ipfile) && ev.Op&(fsnotify.Write|fsnotify.Create) != 0 {
|
||
|
log.Println("IPs file changes, reloading them!")
|
||
|
go app.tryReloadIPList(ipfile)
|
||
|
}
|
||
|
case err := <-watcher.Errors:
|
||
|
log.Println("watcher error:", err)
|
||
|
}
|
||
|
}
|
||
|
}()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (app *App) tryReloadIPList(ipfile string) {
|
||
|
if _, err := os.Stat(ipfile); !os.IsNotExist(err) {
|
||
|
if iplist, err := loadIPs(ipfile); err != nil {
|
||
|
log.Println("ERROR: Unable to read ip file:", err)
|
||
|
} else {
|
||
|
log.Printf("Loading %d IPs to authorized list", len(iplist))
|
||
|
app.ips = iplist
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func loadIPs(file string) ([]string, error) {
|
||
|
fd, err := os.Open(file)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
defer fd.Close()
|
||
|
|
||
|
var ret []string
|
||
|
jdec := json.NewDecoder(fd)
|
||
|
|
||
|
if err := jdec.Decode(&ret); err != nil {
|
||
|
return ret, err
|
||
|
}
|
||
|
|
||
|
return ret, nil
|
||
|
}
|
||
|
|
||
|
func (app *App) Restrict2IPs(c *gin.Context) {
|
||
|
found := false
|
||
|
for _, ip := range app.ips {
|
||
|
if strings.HasPrefix(c.Request.RemoteAddr, ip) {
|
||
|
found = true
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if found {
|
||
|
c.Next()
|
||
|
} else {
|
||
|
c.AbortWithError(http.StatusForbidden, fmt.Errorf("IP not authorized: %s", c.Request.RemoteAddr))
|
||
|
}
|
||
|
}
|