Skip to content

Commit 496ddad

Browse files
authored
Merge pull request #7 from opensciencegrid/addIpMapping
Add IP mapping
2 parents 9446a81 + 74027bb commit 496ddad

File tree

6 files changed

+168
-3
lines changed

6 files changed

+168
-3
lines changed

config/config.yaml

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,15 @@ metrics:
2929
# the queue will be emptied. The queue on disk is persistent between restarts.
3030
config_directory: /tmp/shoveler-queue
3131

32-
32+
# Mapping configuration
33+
# If map.all is set, all messages will be mapped to the configured origin.
34+
# For example, with the configuration
35+
# map:
36+
# all: 172.0.0.4
37+
# If a packet comes in with the private ip address of 192.168.0.4, the packet origin will be changed to 172.0.0.4
38+
# The port is always preserved.
39+
# If you want multiple mappings, you can specify multiple map entries.
40+
# For example, with the configuration
41+
# map:
42+
# 192.168.0.5: 172.0.0.5
43+
# 192.168.0.6: 129.93.10.7

main.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ func main() {
2323
} else {
2424
log.SetLevel(log.WarnLevel)
2525
}
26+
27+
// Configure the mapper
28+
configureMap()
29+
2630
textFormatter := log.TextFormatter{}
2731
textFormatter.DisableLevelTruncation = true
2832
textFormatter.FullTimestamp = true
@@ -57,7 +61,12 @@ func main() {
5761
panic(err)
5862
}
5963

60-
defer conn.Close()
64+
defer func(conn *net.UDPConn) {
65+
err := conn.Close()
66+
if err != nil {
67+
log.Errorln("Error closing UDP connection:", err)
68+
}
69+
}(conn)
6170

6271
// Create the UDP forwarding destinations
6372
var udpDestinations []net.Conn

map.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package main
2+
3+
import (
4+
"net"
5+
6+
"github.com/spf13/viper"
7+
)
8+
9+
var (
10+
mapAll string
11+
ipMap map[string]string
12+
)
13+
14+
// configureMap sets the mapping configuration
15+
func configureMap() {
16+
// First, check for the map environment variable
17+
mapAll = viper.GetString("map.all")
18+
19+
// If the map is not set
20+
ipMap = viper.GetStringMapString("map")
21+
22+
}
23+
24+
// mapIp returns the mapped IP address
25+
func mapIp(remote *net.UDPAddr) string {
26+
27+
if mapAll != "" {
28+
return mapAll
29+
}
30+
if len(ipMap) == 0 {
31+
return remote.IP.String()
32+
}
33+
if ip, ok := ipMap[remote.IP.String()]; ok {
34+
return ip
35+
}
36+
return remote.IP.String()
37+
}

map_test.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package main
2+
3+
import (
4+
"bytes"
5+
"github.com/spf13/viper"
6+
"net"
7+
"os"
8+
"testing"
9+
10+
"github.com/stretchr/testify/assert"
11+
)
12+
13+
func TestSingleIp(t *testing.T) {
14+
ip := net.UDPAddr{IP: net.ParseIP("192.168.0.5"), Port: 514}
15+
16+
// If the map is not set
17+
config := Config{}
18+
config.ReadConfig()
19+
configureMap()
20+
ipStr := mapIp(&ip)
21+
assert.Equal(t, "192.168.0.5", ipStr, "Test when map is not set")
22+
23+
// If the map is set by environment variable
24+
err := os.Setenv("SHOVELER_MAP_ALL", "172.168.0.5")
25+
assert.NoError(t, err, "Failed to set environment variable SHOVELER_MAP_ALL")
26+
config.ReadConfig()
27+
configureMap()
28+
ipStr = mapIp(&ip)
29+
assert.Equal(t, "172.168.0.5", ipStr, "Test when map is set by environment variable")
30+
31+
// If the map is set by config file
32+
err = os.Unsetenv("SHOVELER_MAP_ALL")
33+
assert.NoError(t, err, "Failed to unset SHOVELER_MAP_ALL")
34+
// any approach to require this configuration into your program.
35+
var yamlExample = []byte(`
36+
map:
37+
192.168.1.5: 172.168.1.6
38+
172.168.2.7: 129.93.10.5
39+
`)
40+
err = viper.ReadConfig(bytes.NewBuffer(yamlExample))
41+
defer viper.Reset()
42+
assert.NoError(t, err, "Failed to read config file")
43+
configureMap()
44+
defer func() {
45+
ipMap = nil
46+
mapAll = ""
47+
}()
48+
ip = net.UDPAddr{IP: net.ParseIP("192.168.1.5"), Port: 514}
49+
assert.Equal(t, "172.168.1.6", mapIp(&ip), "Test when map is set by config file")
50+
ip = net.UDPAddr{IP: net.ParseIP("172.168.2.7"), Port: 514}
51+
assert.Equal(t, "129.93.10.5", mapIp(&ip), "Test when map is set by config file")
52+
}

packageudp.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ func packageUdp(packet []byte, remote *net.UDPAddr) []byte {
2222
msg.Data = str
2323

2424
// add the remote
25-
msg.Remote = remote.IP.String()
25+
msg.Remote = mapIp(remote)
2626
msg.Remote += ":" + strconv.Itoa(remote.Port)
2727

2828
msg.ShovelerVersion = version

packageudp_test.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package main
2+
3+
import (
4+
"encoding/json"
5+
"github.com/stretchr/testify/assert"
6+
"net"
7+
"testing"
8+
)
9+
10+
func TestPackageUdp(t *testing.T) {
11+
12+
// No mapping enabled
13+
ip := net.UDPAddr{IP: net.ParseIP("192.168.0.7"), Port: 12345}
14+
packaged := packageUdp([]byte("asdf"), &ip)
15+
assert.NotEmpty(t, packaged)
16+
// Parse back the json
17+
var pkg Message
18+
err := json.Unmarshal(packaged, &pkg)
19+
assert.NoError(t, err)
20+
assert.Equal(t, ip.String(), pkg.Remote, "Remote IP should be the same")
21+
assert.Equal(t, "YXNkZg==", pkg.Data, "Data should be base64 encoded")
22+
}
23+
24+
func TestPackageUdp_Mapping(t *testing.T) {
25+
// Mapping enabled
26+
ip := net.UDPAddr{IP: net.ParseIP("192.168.0.8"), Port: 12345}
27+
mapAll = "172.0.0.9"
28+
packaged := packageUdp([]byte("asdf"), &ip)
29+
assert.NotEmpty(t, packaged)
30+
// Parse back the json
31+
var pkg Message
32+
err := json.Unmarshal(packaged, &pkg)
33+
assert.NoError(t, err)
34+
assert.Equal(t, "172.0.0.9:12345", pkg.Remote, "Remote IP should be the same")
35+
assert.Equal(t, "YXNkZg==", pkg.Data, "Data should be base64 encoded")
36+
mapAll = ""
37+
}
38+
39+
func TestPackageUdp_MappingMultiple(t *testing.T) {
40+
// Mapping enabled
41+
ip := net.UDPAddr{IP: net.ParseIP("192.168.0.8"), Port: 12345}
42+
ipMap = make(map[string]string)
43+
defer func() {
44+
ipMap = nil
45+
}()
46+
ipMap["192.168.0.8"] = "172.0.0.10"
47+
ipMap["192.168.0.9"] = "172.0.0.11"
48+
packaged := packageUdp([]byte("asdf"), &ip)
49+
assert.NotEmpty(t, packaged)
50+
// Parse back the json
51+
var pkg Message
52+
err := json.Unmarshal(packaged, &pkg)
53+
assert.NoError(t, err)
54+
assert.Equal(t, "172.0.0.10:12345", pkg.Remote, "Remote IP should be the same")
55+
assert.Equal(t, "YXNkZg==", pkg.Data, "Data should be base64 encoded")
56+
}

0 commit comments

Comments
 (0)