1// Copyright 2011 The Go Authors.  All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// +build darwin dragonfly freebsd linux netbsd openbsd
6
7package net
8
9import (
10	"errors"
11	"sync"
12)
13
14var onceReadProtocols sync.Once
15
16// readProtocols loads contents of /etc/protocols into protocols map
17// for quick access.
18func readProtocols() {
19	if file, err := open("/etc/protocols"); err == nil {
20		for line, ok := file.readLine(); ok; line, ok = file.readLine() {
21			// tcp    6   TCP    # transmission control protocol
22			if i := byteIndex(line, '#'); i >= 0 {
23				line = line[0:i]
24			}
25			f := getFields(line)
26			if len(f) < 2 {
27				continue
28			}
29			if proto, _, ok := dtoi(f[1], 0); ok {
30				if _, ok := protocols[f[0]]; !ok {
31					protocols[f[0]] = proto
32				}
33				for _, alias := range f[2:] {
34					if _, ok := protocols[alias]; !ok {
35						protocols[alias] = proto
36					}
37				}
38			}
39		}
40		file.close()
41	}
42}
43
44// lookupProtocol looks up IP protocol name in /etc/protocols and
45// returns correspondent protocol number.
46func lookupProtocol(name string) (proto int, err error) {
47	onceReadProtocols.Do(readProtocols)
48	proto, found := protocols[name]
49	if !found {
50		return 0, errors.New("unknown IP protocol specified: " + name)
51	}
52	return
53}
54
55func lookupHost(host string) (addrs []string, err error) {
56	addrs, err, ok := cgoLookupHost(host)
57	if !ok {
58		addrs, err = goLookupHost(host)
59	}
60	return
61}
62
63func lookupIP(host string) (addrs []IP, err error) {
64	addrs, err, ok := cgoLookupIP(host)
65	if !ok {
66		addrs, err = goLookupIP(host)
67	}
68	return
69}
70
71func lookupPort(network, service string) (port int, err error) {
72	port, err, ok := cgoLookupPort(network, service)
73	if !ok {
74		port, err = goLookupPort(network, service)
75	}
76	return
77}
78
79func lookupCNAME(name string) (cname string, err error) {
80	cname, err, ok := cgoLookupCNAME(name)
81	if !ok {
82		cname, err = goLookupCNAME(name)
83	}
84	return
85}
86
87func lookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) {
88	var target string
89	if service == "" && proto == "" {
90		target = name
91	} else {
92		target = "_" + service + "._" + proto + "." + name
93	}
94	var records []dnsRR
95	cname, records, err = lookup(target, dnsTypeSRV)
96	if err != nil {
97		return
98	}
99	addrs = make([]*SRV, len(records))
100	for i, rr := range records {
101		r := rr.(*dnsRR_SRV)
102		addrs[i] = &SRV{r.Target, r.Port, r.Priority, r.Weight}
103	}
104	byPriorityWeight(addrs).sort()
105	return
106}
107
108func lookupMX(name string) (mx []*MX, err error) {
109	_, records, err := lookup(name, dnsTypeMX)
110	if err != nil {
111		return
112	}
113	mx = make([]*MX, len(records))
114	for i, rr := range records {
115		r := rr.(*dnsRR_MX)
116		mx[i] = &MX{r.Mx, r.Pref}
117	}
118	byPref(mx).sort()
119	return
120}
121
122func lookupNS(name string) (ns []*NS, err error) {
123	_, records, err := lookup(name, dnsTypeNS)
124	if err != nil {
125		return
126	}
127	ns = make([]*NS, len(records))
128	for i, r := range records {
129		r := r.(*dnsRR_NS)
130		ns[i] = &NS{r.Ns}
131	}
132	return
133}
134
135func lookupTXT(name string) (txt []string, err error) {
136	_, records, err := lookup(name, dnsTypeTXT)
137	if err != nil {
138		return
139	}
140	txt = make([]string, len(records))
141	for i, r := range records {
142		txt[i] = r.(*dnsRR_TXT).Txt
143	}
144	return
145}
146
147func lookupAddr(addr string) (name []string, err error) {
148	name = lookupStaticAddr(addr)
149	if len(name) > 0 {
150		return
151	}
152	var arpa string
153	arpa, err = reverseaddr(addr)
154	if err != nil {
155		return
156	}
157	var records []dnsRR
158	_, records, err = lookup(arpa, dnsTypePTR)
159	if err != nil {
160		return
161	}
162	name = make([]string, len(records))
163	for i := range records {
164		r := records[i].(*dnsRR_PTR)
165		name[i] = r.Ptr
166	}
167	return
168}
169