@@ -18,23 +18,39 @@ import (
18
18
"bytes"
19
19
"fmt"
20
20
"io/ioutil"
21
- "log"
21
+ "os"
22
+ "path"
22
23
"regexp"
23
24
"strings"
25
+ "time"
24
26
27
+ "github.com/netsec-ethz/rains/pkg/rains"
25
28
libaddr "github.com/scionproto/scion/go/lib/addr"
29
+ "github.com/scionproto/scion/go/lib/snet"
26
30
)
27
31
28
32
type scionAddress struct {
29
33
ia libaddr.IA
30
34
l3 libaddr.HostAddr
31
35
}
32
36
37
+ // hosts file
33
38
var (
34
39
hostFilePath = "/etc/hosts"
35
40
addrRegexp = regexp .MustCompile (`^(?P<ia>\d+-[\d:A-Fa-f]+),\[(?P<host>[^\]]+)\]` )
36
- hosts map [string ]scionAddress // hostname -> scionAddress
37
- revHosts map [string ][]string // SCION address w/o port -> hostnames
41
+ hosts = make (map [string ]scionAddress ) // hostname -> scionAddress
42
+ revHosts = make (map [string ][]string ) // SCION address w/o port -> hostnames
43
+ )
44
+
45
+ // RAINS
46
+ var (
47
+ rainsConfigPath = path .Join (os .Getenv ("SC" ), "gen" , "rains.cfg" )
48
+ ctx = "." // use global context
49
+ qType = rains .OTScionAddr4 // request SCION IPv4 addresses
50
+ qOpts = []rains.Option {} // no options
51
+ expire = 5 * time .Minute // sensible expiry date?
52
+ timeout = 500 * time .Millisecond // timeout for query
53
+ rainsServer * snet.Addr // resolver address
38
54
)
39
55
40
56
const (
@@ -43,19 +59,20 @@ const (
43
59
)
44
60
45
61
func init () {
62
+ // parse hosts file
46
63
hostsFile , err := readHostsFile ()
47
- if err != nil {
48
- hostsFile = []byte {}
49
- }
50
- parseHostsFile (hostsFile )
51
- if err != nil {
52
- log .Fatal (err )
64
+ if err == nil {
65
+ parseHostsFile (hostsFile )
53
66
}
67
+
68
+ // read RAINS server address
69
+ rainsServer = readRainsConfig ()
54
70
}
55
71
56
72
// AddHost adds a host to the map of known hosts
57
73
// An error is returned if the address has a wrong format or
58
74
// the hostname already exists
75
+ // The added host will not persist between program executions
59
76
func AddHost (hostname , address string ) error {
60
77
if addrs , ok := hosts [hostname ]; ok {
61
78
return fmt .Errorf ("Host %q already exists, address(es): %v" , hostname , addrs )
@@ -72,14 +89,35 @@ func AddHost(hostname, address string) error {
72
89
73
90
// GetHostByName returns the IA and HostAddr corresponding to hostname
74
91
func GetHostByName (hostname string ) (libaddr.IA , libaddr.HostAddr , error ) {
92
+ // try to resolve hostname locally
75
93
addr , ok := hosts [hostname ]
76
- if ! ok {
77
- return libaddr.IA {}, nil , fmt .Errorf ("Address for host %q not found" , hostname )
94
+ if ok {
95
+ return addr .ia , addr .l3 , nil
96
+ }
97
+
98
+ if rainsServer == nil {
99
+ return libaddr.IA {}, nil , fmt .Errorf ("Could not resolve %q, no RAINS server configured" , hostname )
78
100
}
79
- return addr .ia , addr .l3 , nil
101
+
102
+ // fall back to RAINS
103
+
104
+ // TODO(chaehni): This call can sometimes cause a timeout even though the server is reachable (see issue #221)
105
+ // The timeout value has been decreased to counter this behavior until the problem is resolved.
106
+ reply , err := rains .Query (hostname , ctx , []rains.Type {qType }, qOpts , expire , timeout , rainsServer )
107
+ if err != nil {
108
+ return libaddr.IA {}, nil , fmt .Errorf ("Address for host %q not found: %v" , hostname , err )
109
+ }
110
+ scionAddr , err := addrFromString (reply [qType ])
111
+ if err != nil {
112
+ return libaddr.IA {}, nil , fmt .Errorf ("Address for host %q invalid: %v" , hostname , err )
113
+ }
114
+
115
+ return scionAddr .ia , scionAddr .l3 , nil
116
+
80
117
}
81
118
82
119
// GetHostnamesByAddress returns the hostnames corresponding to address
120
+ // TODO: (chaehni) RAINS address query to resolve address to name
83
121
func GetHostnamesByAddress (address string ) ([]string , error ) {
84
122
match := addrRegexp .FindString (address )
85
123
host , ok := revHosts [match ]
@@ -98,8 +136,6 @@ func readHostsFile() ([]byte, error) {
98
136
}
99
137
100
138
func parseHostsFile (hostsFile []byte ) {
101
- hosts = make (map [string ]scionAddress )
102
- revHosts = make (map [string ][]string )
103
139
lines := bytes .Split (hostsFile , []byte ("\n " ))
104
140
for _ , line := range lines {
105
141
fields := strings .Fields (string (line ))
@@ -124,8 +160,23 @@ func parseHostsFile(hostsFile []byte) {
124
160
}
125
161
}
126
162
163
+ func readRainsConfig () * snet.Addr {
164
+ bs , err := ioutil .ReadFile (rainsConfigPath )
165
+ if err != nil {
166
+ return nil
167
+ }
168
+ addr , err := snet .AddrFromString (strings .TrimSpace (string (bs )))
169
+ if err != nil {
170
+ return nil
171
+ }
172
+ return addr
173
+ }
174
+
127
175
func addrFromString (addr string ) (scionAddress , error ) {
128
176
parts := addrRegexp .FindStringSubmatch (addr )
177
+ if parts == nil {
178
+ return scionAddress {}, fmt .Errorf ("No valid SCION address: %q" , addr )
179
+ }
129
180
ia , err := libaddr .IAFromString (parts [iaIndex ])
130
181
if err != nil {
131
182
return scionAddress {}, fmt .Errorf ("Invalid IA string: %v" , parts [iaIndex ])
0 commit comments