Skip to content

Commit 0c817c4

Browse files
committed
[dns] #support dns lookup
1 parent 99e8ec3 commit 0c817c4

File tree

7 files changed

+222
-50
lines changed

7 files changed

+222
-50
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
## @application 应用层
1717
- [x] [http](http://wiki.brewlin.com/wiki/net-protocol/index/)
1818
- [x] [websocket](http://wiki.brewlin.com/wiki/net-protocol/index/)
19-
- [ ] [dns](http://wiki.brewlin.com/wiki/net-protocol/index/)
19+
- [x] [dns](http://wiki.brewlin.com/wiki/net-protocol/index/)
2020

2121

2222
## @transport 传输层

cmd/application/dns/main.go

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,27 @@ package main
33
import (
44
"fmt"
55
"github.com/brewlin/net-protocol/protocol/application/dns"
6+
"github.com/brewlin/net-protocol/protocol/header"
67
)
78

89
func main() {
9-
dns := dns.NewEndpoint("www.baidu.com")
10-
ir,err := dns.Resolve();
11-
fmt.Println(err)
12-
fmt.Println(string(ir))
10+
d := dns.NewEndpoint("www.baidu.com")
11+
fmt.Println("DNS lookuphost : www.baidu.com")
12+
defer d.Close()
13+
14+
ir,err := d.Resolve();
15+
if err != nil {
16+
fmt.Println(err)
17+
return
18+
}
19+
for _,v := range *ir {
20+
switch v.Type {
21+
case header.A:
22+
fmt.Println("A(host name) :",v.Address)
23+
case header.CNAME:
24+
fmt.Println("CNAME (alias name):",v.Address)
25+
}
26+
}
1327

1428

1529
}

protocol/application/dns/endopoint.go

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,52 @@
11
package dns
22

33
import (
4+
_ "github.com/brewlin/net-protocol/pkg/logging"
45
"github.com/brewlin/net-protocol/protocol/header"
56
"github.com/brewlin/net-protocol/protocol/transport/udp/client"
6-
_ "github.com/brewlin/net-protocol/pkg/logging"
77
)
88
var gid uint16 = 0x0010
99

1010
type Endpoint struct {
1111
ID uint16
1212
Domain string
1313

14+
//req data
15+
req *header.DNS
16+
resp *header.DNS
17+
18+
answer *[]header.DNSResource
19+
1420
c *client.Client
1521
}
1622
//NewEndpoint
23+
//support single domain query
1724
func NewEndpoint(domain string)*Endpoint{
1825
id := gid + 1
1926
return &Endpoint{
2027
Domain:domain,
2128
c:client.NewClient("8.8.8.8",53),
29+
//c:client.NewClient("114.114.114.114",53),
2230
ID:id,
2331
}
2432
}
2533
//Resolve
26-
func (e *Endpoint) Resolve()([]byte,error){
34+
func (e *Endpoint) Resolve() ( *[]header.DNSResource,error ) {
35+
2736
h := header.DNS(make([]byte,12))
2837
h.Setheader(e.ID)
29-
h.SetQdcount(1)
30-
h.SetAncount(0)
31-
h.SetNscount(0)
32-
h.SetQAcount(0)
33-
h.SetDomain(e.Domain)
34-
h.SetQuestion(1,1)
35-
e.c.Connect()
36-
e.c.Write(h)
37-
return e.c.Read()
38-
39-
38+
h.SetCount(1,0,0,0)
39+
h.SetQuestion(e.Domain,1,1)
40+
e.req = &h
41+
return e.sendQuery()
42+
}
43+
//GetResp()
44+
func (e *Endpoint) GetResp() *header.DNS{
45+
return e.resp
46+
}
47+
//Close close
48+
func (e *Endpoint) Close(){
49+
e.c.Close()
4050
}
4151

4252

protocol/application/dns/query.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package dns
2+
3+
import "github.com/brewlin/net-protocol/protocol/header"
4+
5+
//sendQuery udp query dns
6+
func (e *Endpoint) sendQuery () ( *[]header.DNSResource ,error ) {
7+
8+
if err := e.c.Connect();err != nil {
9+
return nil,err
10+
}
11+
if err := e.c.Write(*e.req) ; err != nil {
12+
return nil,err
13+
}
14+
return e.parseResp()
15+
}

protocol/application/dns/rsp.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package dns
2+
3+
import (
4+
"github.com/brewlin/net-protocol/protocol/header"
5+
"strconv"
6+
"strings"
7+
)
8+
9+
//parseResp
10+
//解析响应
11+
func (e *Endpoint) parseResp() (*[]header.DNSResource,error){
12+
rsp,err := e.c.Read()
13+
if err != nil {
14+
return nil,err
15+
}
16+
p := header.DNS(rsp)
17+
e.resp = &p
18+
e.answer = p.GetAnswer(e.Domain)
19+
return e.parseAnswer()
20+
}
21+
22+
func (e *Endpoint) parseAnswer()(*[]header.DNSResource,error){
23+
for i := 0; i < len(*e.answer) ; i++ {
24+
switch (*e.answer)[i].Type {
25+
case header.A:
26+
(*e.answer)[i].Address = e.parseAName((*e.answer)[i].RData)
27+
case header.CNAME:
28+
(*e.answer)[i].Address = e.parseCName((*e.answer)[i].RData)
29+
}
30+
}
31+
return e.answer,nil
32+
}
33+
func (e *Endpoint)parseAName(rd []byte) string {
34+
res := []string{}
35+
for _,v := range rd {
36+
res = append(res,strconv.Itoa(int(v)))
37+
}
38+
return strings.Join(res,".")
39+
}
40+
41+
func (e *Endpoint)parseCName(rd []byte) (res string) {
42+
43+
for{
44+
l := int(rd[0])
45+
if l >= len(rd){
46+
res += ".com"
47+
return
48+
}
49+
rd = rd[1:]
50+
res += string(rd[0:l])
51+
rd = rd[l:]
52+
if len(rd) == 0 {
53+
return
54+
}
55+
56+
}
57+
}

protocol/header/dns.go

Lines changed: 107 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -6,82 +6,158 @@ import (
66
"strings"
77
)
88

9-
//DNSResourceType resource type 表示资源类型
10-
type DNSResourceType uint16
11-
12-
//DNSop 表示dns header 操作码
13-
type DNSop uint16
149

1510
//ADCOUNT question 实体数量占2个字节
1611
//ANCOUNT answer 资源数量占2个字节
1712
//NSCOUNT authority 部分包含的资源数量 2byte
1813
//ARCOUNT additional 部分包含的资源梳理 2byte
1914

15+
//DNSResourceType resource type 表示资源类型
16+
type DNSResourceType uint16
17+
18+
const (
19+
A DNSResourceType = iota + 1 // name = hostname value = ipaddress
20+
NS //name = ,value = dns hostname
21+
MD
22+
MF
23+
CNAME //name = hostname
24+
SOA
25+
MB
26+
MG
27+
MR
28+
NULL
29+
WKS
30+
PTR
31+
HINFO
32+
MINFO
33+
MX
34+
)
2035

2136
const (
2237
ID = 0
2338
OP = 2
2439
QDCOUNT = 4
2540
ANCOUNT = 6
2641
NSCOUNT = 8
27-
QACOUNT = 10
42+
ARCOUNT = 10
2843

2944
DOMAIN = 12
3045
)
31-
46+
//DNSQuestion
3247
type DNSQuestion struct {
3348
QuestionType uint16
3449
QuestionClass uint16
3550
}
3651

52+
//DNSResource ansower,authority,additional
53+
type DNSResource struct {
54+
Name uint16
55+
Type DNSResourceType
56+
Class uint16
57+
TTL uint32
58+
RDlen uint16
59+
RData []byte
60+
Address string
61+
}
62+
63+
3764
//DNS 报文的封装
3865
type DNS []byte
3966

67+
//GetId
68+
func (d DNS) GetId() uint16 {
69+
return binary.BigEndian.Uint16(d[ID:OP])
70+
}
71+
//GetQDCount
72+
func (d DNS) GetQDCount()uint16 {
73+
return binary.BigEndian.Uint16(d[QDCOUNT:QDCOUNT+2])
74+
}
75+
//GetANCount
76+
func (d DNS) GetANCount()uint16{
77+
return binary.BigEndian.Uint16(d[ANCOUNT:ANCOUNT + 2])
78+
}
79+
//GetNSCount
80+
func (d DNS) GetNSCount() uint16 {
81+
return binary.BigEndian.Uint16(d[NSCOUNT:NSCOUNT + 2])
82+
}
83+
//GetQACount
84+
func (d DNS) GetARCount () uint16 {
85+
return binary.BigEndian.Uint16(d[ARCOUNT:ARCOUNT + 2])
86+
}
87+
88+
//GetAnswer
89+
func (d DNS) GetAnswer(domain string) *[]DNSResource {
90+
//answer 起始地址
91+
asLen := DOMAIN + len(d.getDomain(domain)) + 4
92+
93+
answer := []DNSResource{}
94+
for i := 0; i < (int(d.GetANCount() + d.GetNSCount() + d.GetARCount())) ;i ++ {
95+
rs := DNSResource{}
96+
//判断是不是指针 pointer地址
97+
if checkP := d[asLen]; checkP >> 6 == 3 {
98+
//pointer := (d[asLen] & 0x3F << 8) + d[asLen+1]
99+
rs.Name = binary.BigEndian.Uint16(d[asLen:asLen+2])
100+
asLen += 2
101+
rs.Type = DNSResourceType(binary.BigEndian.Uint16(d[asLen:asLen+2]))
102+
asLen += 2
103+
rs.Class = binary.BigEndian.Uint16(d[asLen:asLen+2])
104+
asLen += 2
105+
rs.TTL = binary.BigEndian.Uint32(d[asLen:asLen+4])
106+
asLen += 4
107+
rs.RDlen = binary.BigEndian.Uint16(d[asLen:asLen+2])
108+
asLen += 2
109+
rs.RData = d[asLen:asLen+int(rs.RDlen)]
110+
asLen += int(rs.RDlen)
111+
answer = append(answer,rs)
112+
}
113+
}
114+
return &answer
115+
}
116+
40117
//Setheader
41118
func (d DNS) Setheader(id uint16){
42119
d.setID(id)
43120
d.setFlag(0,0,0,0,1,0,0)
44121
}
45-
//SetID
46-
func (d DNS)setID(id uint16){
47-
//set id
48-
binary.BigEndian.PutUint16(d[ID:], id)
49-
}
50-
//SetQdcount
51-
func (d DNS)SetQdcount(qd uint16){
52-
122+
//SetCount
123+
func (d DNS) SetCount(qd,an,ns,qa uint16) {
124+
//SetQdcount
53125
binary.BigEndian.PutUint16(d[QDCOUNT:], qd)
54-
}
55-
//SetAncount
56-
func (d DNS)SetAncount(an uint16){
126+
//SetAncount
57127
binary.BigEndian.PutUint16(d[ANCOUNT:] ,an)
58-
}
59-
//SetNscount
60-
func (d DNS)SetNscount(ns uint16){
128+
//SetNscount
61129
binary.BigEndian.PutUint16(d[NSCOUNT:],ns)
130+
//SetQAcount
131+
binary.BigEndian.PutUint16(d[ARCOUNT:],qa)
62132
}
63-
//SetQAcount
64-
func (d DNS)SetQAcount(qa uint16){
65-
binary.BigEndian.PutUint16(d[QACOUNT:],qa)
133+
//setID
134+
func (d DNS)setID(id uint16){
135+
//set id
136+
binary.BigEndian.PutUint16(d[ID:], id)
66137
}
67-
//SetDomain
68-
func (d *DNS)SetDomain(domain string) {
138+
//setDomain
139+
func (d *DNS)getDomain(domain string) []byte {
69140
var (
70141
buffer bytes.Buffer
71142
segments []string = strings.Split(domain, ".")
72143
)
73-
binary.Write(&buffer,binary.BigEndian,*d)
74-
75144
for _, seg := range segments {
76145
binary.Write(&buffer, binary.BigEndian, byte(len(seg)))
77146
binary.Write(&buffer, binary.BigEndian, []byte(seg))
78147
}
79148
binary.Write(&buffer, binary.BigEndian, byte(0x00))
80149

81-
*d = buffer.Bytes()
82-
//return buffer.Bytes()
150+
return buffer.Bytes()
83151
}
84-
func (d *DNS)SetQuestion(qtype,qclass uint16){
152+
//SetQuestion query field
153+
//domain url
154+
//qtype type
155+
//qclass class
156+
func (d *DNS)SetQuestion(domain string,qtype,qclass uint16){
157+
for _,b := range d.getDomain(domain) {
158+
*d = append((*d),b)
159+
}
160+
//d.setDomain(domain)
85161
q := DNSQuestion{
86162
QuestionType: qtype,
87163
QuestionClass: qclass,

protocol/transport/udp/client/write.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import (
55
tcpip "github.com/brewlin/net-protocol/protocol"
66
)
77
//Write
8-
func (c *Client) Write(buf []byte) error {
8+
func (c *Client) Write(buf []byte) *tcpip.Error {
99
v := buffer.View(buf)
1010
for{
1111
_,ch,err := c.ep.Write(tcpip.SlicePayload(v),

0 commit comments

Comments
 (0)