This repository was archived by the owner on Sep 21, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathnetdb.go
More file actions
196 lines (165 loc) · 4.13 KB
/
netdb.go
File metadata and controls
196 lines (165 loc) · 4.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
// Package netdb provides a Go interface for the protoent and servent
// structures as defined in netdb.h
//
// A pure Go implementation is used by parsing /etc/protocols and
// /etc/services
//
// All return values are pointers that point to the entries in the
// original list of protocols and services. Manipulating the entries
// would affect the entire program.
package netdb // import "honnef.co/go/netdb"
import (
"io/ioutil"
"strconv"
"strings"
)
type Protoent struct {
Name string
Aliases []string
Number int
}
type Servent struct {
Name string
Aliases []string
Port int
Protocol *Protoent
}
// These variables get populated from /etc/protocols and /etc/services
// respectively.
var (
Protocols []*Protoent
Services []*Servent
)
func init() {
protoMap := make(map[string]*Protoent)
// Load protocols
data, err := ioutil.ReadFile("/etc/protocols")
if err != nil {
panic(err)
}
for _, line := range strings.Split(string(data), "\n") {
line = strings.TrimSpace(line)
split := strings.SplitN(line, "#", 2)
fields := strings.Fields(split[0])
if len(fields) < 2 {
continue
}
num, err := strconv.ParseInt(fields[1], 10, 32)
if err != nil {
panic(err)
}
protoent := &Protoent{
Name: fields[0],
Aliases: fields[2:],
Number: int(num),
}
Protocols = append(Protocols, protoent)
protoMap[fields[0]] = protoent
}
// Load services
data, err = ioutil.ReadFile("/etc/services")
if err != nil {
panic(err)
}
for _, line := range strings.Split(string(data), "\n") {
line = strings.TrimSpace(line)
split := strings.SplitN(line, "#", 2)
fields := strings.Fields(split[0])
if len(fields) < 2 {
continue
}
name := fields[0]
portproto := strings.SplitN(fields[1], "/", 2)
port, err := strconv.ParseInt(portproto[0], 10, 32)
if err != nil {
panic(err)
}
proto := portproto[1]
aliases := fields[2:]
Services = append(Services, &Servent{
Name: name,
Aliases: aliases,
Port: int(port),
Protocol: protoMap[proto],
})
}
}
// Equal checks if two Protoents are the same, which is the case if
// their protocol numbers are identical or when both Protoents are
// nil.
func (this *Protoent) Equal(other *Protoent) bool {
if this == nil && other == nil {
return true
}
if this == nil || other == nil {
return false
}
return this.Number == other.Number
}
// Equal checks if two Servents are the same, which is the case if
// their port numbers and protocols are identical or when both
// Servents are nil.
func (this *Servent) Equal(other *Servent) bool {
if this == nil && other == nil {
return true
}
if this == nil || other == nil {
return false
}
return this.Port == other.Port &&
this.Protocol.Equal(other.Protocol)
}
// GetProtoByNumber returns the Protoent for a given protocol number.
func GetProtoByNumber(num int) (protoent *Protoent) {
for _, protoent := range Protocols {
if protoent.Number == num {
return protoent
}
}
return nil
}
// GetProtoByName returns the Protoent whose name or any of its
// aliases matches the argument.
func GetProtoByName(name string) (protoent *Protoent) {
for _, protoent := range Protocols {
if protoent.Name == name {
return protoent
}
for _, alias := range protoent.Aliases {
if alias == name {
return protoent
}
}
}
return nil
}
// GetServByName returns the Servent for a given service name or alias
// and protocol. If the protocol is nil, the first service matching
// the service name is returned.
func GetServByName(name string, protocol *Protoent) (servent *Servent) {
for _, servent := range Services {
if !servent.Protocol.Equal(protocol) {
continue
}
if servent.Name == name {
return servent
}
for _, alias := range servent.Aliases {
if alias == name {
return servent
}
}
}
return nil
}
// GetServByPort returns the Servent for a given port number and
// protocol. If the protocol is nil, the first service matching the
// port number is returned.
func GetServByPort(port int, protocol *Protoent) *Servent {
for _, servent := range Services {
if servent.Port == port && servent.Protocol.Equal(protocol) {
return servent
}
}
return nil
}