Skip to content

Commit

Permalink
Merge pull request #42 from PSNAppz/add_notify_method
Browse files Browse the repository at this point in the history
Add IP Region Blocking
  • Loading branch information
PSNAppz authored Sep 28, 2023
2 parents 29a3f7b + e8cc42c commit c95f497
Show file tree
Hide file tree
Showing 11 changed files with 261 additions and 144 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,6 @@
# vendor/

# Go workspace file
go.work
go.work
monitor-log
.DS_Store
10 changes: 10 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@
"channelID": "C5UTW0J6N"
}]
}
},
{
"type": "requestfilter",
"settings":{
"active_mode": true,
"ip-blacklist":[],
"ip-whitelist": [],
"region-whitelist": ["US", "IN"],
"region-blacklist": []
}
}],
"methods": ["GET"],
"external": "/external",
Expand Down
7 changes: 6 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ go 1.20

require (
github.com/gorilla/mux v1.8.0
github.com/oschwald/geoip2-golang v1.9.0
github.com/slack-go/slack v0.12.2
)

require github.com/gorilla/websocket v1.5.0 // indirect
require (
github.com/gorilla/websocket v1.5.0 // indirect
github.com/oschwald/maxminddb-golang v1.11.0 // indirect
golang.org/x/sys v0.9.0 // indirect
)
9 changes: 8 additions & 1 deletion go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,17 @@ github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB7
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/oschwald/geoip2-golang v1.9.0 h1:uvD3O6fXAXs+usU+UGExshpdP13GAqp4GBrzN7IgKZc=
github.com/oschwald/geoip2-golang v1.9.0/go.mod h1:BHK6TvDyATVQhKNbQBdrj9eAvuwOMi2zSFXizL3K81Y=
github.com/oschwald/maxminddb-golang v1.11.0 h1:aSXMqYR/EPNjGE8epgqwDay+P30hCBZIveY0WZbAWh0=
github.com/oschwald/maxminddb-golang v1.11.0/go.mod h1:YmVI+H0zh3ySFR3w+oz8PCfglAFj3PuCmui13+P9zDg=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/slack-go/slack v0.12.2 h1:x3OppyMyGIbbiyFhsBmpf9pwkUzMhthJMRNmNlA4LaQ=
github.com/slack-go/slack v0.12.2/go.mod h1:hlGi5oXA+Gt+yWTPP0plCdRKmjsDxecdHxYQdlMQKOw=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
2 changes: 1 addition & 1 deletion pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,6 @@ func Init() *Config {

var config Config
json.Unmarshal(byteData, &config)
log.Printf("Configuration file loaded. %+v\n", config)
log.Printf("Configuration file loaded.\n")
return &config
}
10 changes: 6 additions & 4 deletions pkg/middleware/intercept_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@ func TestInterceptWithActivePlugins(t *testing.T) {
method := "GET"
pluginConfigs := []config.PluginConfig{
{
Type: "ipfilter",
Type: "requestfilter",
Settings: map[string]interface{}{
"active_mode": true,
"blacklist": []interface{}{"127.0.0.1"},
"whitelist": []interface{}{},
"active_mode": true,
"ip-blacklist": []interface{}{"127.0.0.1"},
"ip-whitelist": []interface{}{},
"region-whitelist": []interface{}{},
"region-blacklist": []interface{}{},
},
},
}
Expand Down
Binary file added plugins/ipfilter/GeoLite2-Country.mmdb
Binary file not shown.
85 changes: 0 additions & 85 deletions plugins/ipfilter/ipfilter.go

This file was deleted.

51 changes: 0 additions & 51 deletions plugins/ipfilter/ipfilter_test.go

This file was deleted.

156 changes: 156 additions & 0 deletions plugins/ipfilter/requestfilter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
package requestfilter

import (
"errors"
"log"
"net"
"net/http"
"os"
"path/filepath"
"runtime"
"shadowguard/pkg/plugin"
"shadowguard/pkg/publisher"

"github.com/oschwald/geoip2-golang"
)

var dbPath = "plugins/ipfilter/GeoLite2-Country.mmdb"
var Type string = "requestfilter"

func init() {
plugin.RegisterPlugin(Type, NewRequestFilterPlugin)
}

type RequestFilterPlugin struct {
Settings map[string]interface{}
activeMode bool
ipBlacklist []interface{}
ipWhitelist []interface{}
regionWhitelist []interface{}
regionBlacklist []interface{}
publishers []publisher.Publisher
}

func NewRequestFilterPlugin(settings map[string]interface{}) plugin.Plugin {
publishers, err := publisher.CreatePublishers(settings)
if err != nil {
panic(err)
}

ipBlacklist, _ := settings["ip-blacklist"].([]interface{})
ipWhitelist, _ := settings["ip-whitelist"].([]interface{})
regionWhitelist, _ := settings["region-whitelist"].([]interface{})
regionBlacklist, _ := settings["region-blacklist"].([]interface{})

return &RequestFilterPlugin{
Settings: settings,
activeMode: settings["active_mode"].(bool),
ipBlacklist: ipBlacklist,
ipWhitelist: ipWhitelist,
regionWhitelist: regionWhitelist,
regionBlacklist: regionBlacklist,
publishers: publishers,
}
}

func (p *RequestFilterPlugin) Type() string {
return Type
}

func (p *RequestFilterPlugin) IsActiveMode() bool {
return p.activeMode
}

func (p *RequestFilterPlugin) Notify(message string) {
for _, pub := range p.publishers {
err := pub.Publish(message)
if err != nil {
log.Printf("unable to notify publisher. message %s - error: %v", message, err)
}
}
}

func (p *RequestFilterPlugin) Handle(r *http.Request) error {
ip, _, err := net.SplitHostPort(r.RemoteAddr)
if err != nil {
return err
}

// Handle IP-based restrictions
if len(p.ipBlacklist) > 0 {
for _, blacklistedIP := range p.ipBlacklist {
if ip == blacklistedIP {
return errors.New("IP address is blacklisted")
}
}
}

if len(p.ipWhitelist) > 0 {
isWhitelisted := false
for _, whitelistedIP := range p.ipWhitelist {
if ip == whitelistedIP {
isWhitelisted = true
break
}
}
if !isWhitelisted {
return errors.New("IP address not whitelisted")
}
}

// Handle region-based restrictions
region := getRegionForIP(ip)
if len(p.regionBlacklist) > 0 {

for _, restrictedRegion := range p.regionBlacklist {
if region == restrictedRegion {
log.Printf("region %s is restricted by policy", region)
return errors.New("access from this region is restricted by policy")
}
}
}

if len(p.regionWhitelist) > 0 {
isRegionWhitelisted := false
for _, allowedRegion := range p.regionWhitelist {
if region == allowedRegion {
isRegionWhitelisted = true
break
}
}
if !isRegionWhitelisted {
return errors.New("access from this region is not whitelisted")
}
}

return nil
}

func getRegionForIP(ip string) string {
// Handle PATH for testing
if _, err := os.Stat(dbPath); os.IsNotExist(err) {
_, b, _, _ := runtime.Caller(0)

// Root directory of this source file
root := filepath.Dir(b)
dbPath = filepath.Join(root, "GeoLite2-Country.mmdb")
}
// Open the GeoIP2 database.
db, err := geoip2.Open(dbPath)
if err != nil {
log.Fatal(err)
}
defer db.Close()

// Parse the IP
parsedIP := net.ParseIP(ip)

// Lookup the IP in the database
record, err := db.Country(parsedIP)
if err != nil {
log.Fatal(err)
}

// Return the ISO country code (e.g., "US", "IN")
return record.Country.IsoCode
}
Loading

0 comments on commit c95f497

Please sign in to comment.