Skip to content

Commit

Permalink
[dns] #support dns lookup
Browse files Browse the repository at this point in the history
  • Loading branch information
brewlin committed Mar 6, 2020
1 parent 99e8ec3 commit 0c817c4
Show file tree
Hide file tree
Showing 7 changed files with 222 additions and 50 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
## @application 应用层
- [x] [http](http://wiki.brewlin.com/wiki/net-protocol/index/)
- [x] [websocket](http://wiki.brewlin.com/wiki/net-protocol/index/)
- [ ] [dns](http://wiki.brewlin.com/wiki/net-protocol/index/)
- [x] [dns](http://wiki.brewlin.com/wiki/net-protocol/index/)


## @transport 传输层
Expand Down
22 changes: 18 additions & 4 deletions cmd/application/dns/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,27 @@ package main
import (
"fmt"
"github.com/brewlin/net-protocol/protocol/application/dns"
"github.com/brewlin/net-protocol/protocol/header"
)

func main() {
dns := dns.NewEndpoint("www.baidu.com")
ir,err := dns.Resolve();
fmt.Println(err)
fmt.Println(string(ir))
d := dns.NewEndpoint("www.baidu.com")
fmt.Println("DNS lookuphost : www.baidu.com")
defer d.Close()

ir,err := d.Resolve();
if err != nil {
fmt.Println(err)
return
}
for _,v := range *ir {
switch v.Type {
case header.A:
fmt.Println("A(host name) :",v.Address)
case header.CNAME:
fmt.Println("CNAME (alias name):",v.Address)
}
}


}
36 changes: 23 additions & 13 deletions protocol/application/dns/endopoint.go
Original file line number Diff line number Diff line change
@@ -1,42 +1,52 @@
package dns

import (
_ "github.com/brewlin/net-protocol/pkg/logging"
"github.com/brewlin/net-protocol/protocol/header"
"github.com/brewlin/net-protocol/protocol/transport/udp/client"
_ "github.com/brewlin/net-protocol/pkg/logging"
)
var gid uint16 = 0x0010

type Endpoint struct {
ID uint16
Domain string

//req data
req *header.DNS
resp *header.DNS

answer *[]header.DNSResource

c *client.Client
}
//NewEndpoint
//support single domain query
func NewEndpoint(domain string)*Endpoint{
id := gid + 1
return &Endpoint{
Domain:domain,
c:client.NewClient("8.8.8.8",53),
//c:client.NewClient("114.114.114.114",53),
ID:id,
}
}
//Resolve
func (e *Endpoint) Resolve()([]byte,error){
func (e *Endpoint) Resolve() ( *[]header.DNSResource,error ) {

h := header.DNS(make([]byte,12))
h.Setheader(e.ID)
h.SetQdcount(1)
h.SetAncount(0)
h.SetNscount(0)
h.SetQAcount(0)
h.SetDomain(e.Domain)
h.SetQuestion(1,1)
e.c.Connect()
e.c.Write(h)
return e.c.Read()


h.SetCount(1,0,0,0)
h.SetQuestion(e.Domain,1,1)
e.req = &h
return e.sendQuery()
}
//GetResp()
func (e *Endpoint) GetResp() *header.DNS{
return e.resp
}
//Close close
func (e *Endpoint) Close(){
e.c.Close()
}


Expand Down
15 changes: 15 additions & 0 deletions protocol/application/dns/query.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package dns

import "github.com/brewlin/net-protocol/protocol/header"

//sendQuery udp query dns
func (e *Endpoint) sendQuery () ( *[]header.DNSResource ,error ) {

if err := e.c.Connect();err != nil {
return nil,err
}
if err := e.c.Write(*e.req) ; err != nil {
return nil,err
}
return e.parseResp()
}
57 changes: 57 additions & 0 deletions protocol/application/dns/rsp.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package dns

import (
"github.com/brewlin/net-protocol/protocol/header"
"strconv"
"strings"
)

//parseResp
//解析响应
func (e *Endpoint) parseResp() (*[]header.DNSResource,error){
rsp,err := e.c.Read()
if err != nil {
return nil,err
}
p := header.DNS(rsp)
e.resp = &p
e.answer = p.GetAnswer(e.Domain)
return e.parseAnswer()
}

func (e *Endpoint) parseAnswer()(*[]header.DNSResource,error){
for i := 0; i < len(*e.answer) ; i++ {
switch (*e.answer)[i].Type {
case header.A:
(*e.answer)[i].Address = e.parseAName((*e.answer)[i].RData)
case header.CNAME:
(*e.answer)[i].Address = e.parseCName((*e.answer)[i].RData)
}
}
return e.answer,nil
}
func (e *Endpoint)parseAName(rd []byte) string {
res := []string{}
for _,v := range rd {
res = append(res,strconv.Itoa(int(v)))
}
return strings.Join(res,".")
}

func (e *Endpoint)parseCName(rd []byte) (res string) {

for{
l := int(rd[0])
if l >= len(rd){
res += ".com"
return
}
rd = rd[1:]
res += string(rd[0:l])
rd = rd[l:]
if len(rd) == 0 {
return
}

}
}
138 changes: 107 additions & 31 deletions protocol/header/dns.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,82 +6,158 @@ import (
"strings"
)

//DNSResourceType resource type 表示资源类型
type DNSResourceType uint16

//DNSop 表示dns header 操作码
type DNSop uint16

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

//DNSResourceType resource type 表示资源类型
type DNSResourceType uint16

const (
A DNSResourceType = iota + 1 // name = hostname value = ipaddress
NS //name = ,value = dns hostname
MD
MF
CNAME //name = hostname
SOA
MB
MG
MR
NULL
WKS
PTR
HINFO
MINFO
MX
)

const (
ID = 0
OP = 2
QDCOUNT = 4
ANCOUNT = 6
NSCOUNT = 8
QACOUNT = 10
ARCOUNT = 10

DOMAIN = 12
)

//DNSQuestion
type DNSQuestion struct {
QuestionType uint16
QuestionClass uint16
}

//DNSResource ansower,authority,additional
type DNSResource struct {
Name uint16
Type DNSResourceType
Class uint16
TTL uint32
RDlen uint16
RData []byte
Address string
}


//DNS 报文的封装
type DNS []byte

//GetId
func (d DNS) GetId() uint16 {
return binary.BigEndian.Uint16(d[ID:OP])
}
//GetQDCount
func (d DNS) GetQDCount()uint16 {
return binary.BigEndian.Uint16(d[QDCOUNT:QDCOUNT+2])
}
//GetANCount
func (d DNS) GetANCount()uint16{
return binary.BigEndian.Uint16(d[ANCOUNT:ANCOUNT + 2])
}
//GetNSCount
func (d DNS) GetNSCount() uint16 {
return binary.BigEndian.Uint16(d[NSCOUNT:NSCOUNT + 2])
}
//GetQACount
func (d DNS) GetARCount () uint16 {
return binary.BigEndian.Uint16(d[ARCOUNT:ARCOUNT + 2])
}

//GetAnswer
func (d DNS) GetAnswer(domain string) *[]DNSResource {
//answer 起始地址
asLen := DOMAIN + len(d.getDomain(domain)) + 4

answer := []DNSResource{}
for i := 0; i < (int(d.GetANCount() + d.GetNSCount() + d.GetARCount())) ;i ++ {
rs := DNSResource{}
//判断是不是指针 pointer地址
if checkP := d[asLen]; checkP >> 6 == 3 {
//pointer := (d[asLen] & 0x3F << 8) + d[asLen+1]
rs.Name = binary.BigEndian.Uint16(d[asLen:asLen+2])
asLen += 2
rs.Type = DNSResourceType(binary.BigEndian.Uint16(d[asLen:asLen+2]))
asLen += 2
rs.Class = binary.BigEndian.Uint16(d[asLen:asLen+2])
asLen += 2
rs.TTL = binary.BigEndian.Uint32(d[asLen:asLen+4])
asLen += 4
rs.RDlen = binary.BigEndian.Uint16(d[asLen:asLen+2])
asLen += 2
rs.RData = d[asLen:asLen+int(rs.RDlen)]
asLen += int(rs.RDlen)
answer = append(answer,rs)
}
}
return &answer
}

//Setheader
func (d DNS) Setheader(id uint16){
d.setID(id)
d.setFlag(0,0,0,0,1,0,0)
}
//SetID
func (d DNS)setID(id uint16){
//set id
binary.BigEndian.PutUint16(d[ID:], id)
}
//SetQdcount
func (d DNS)SetQdcount(qd uint16){

//SetCount
func (d DNS) SetCount(qd,an,ns,qa uint16) {
//SetQdcount
binary.BigEndian.PutUint16(d[QDCOUNT:], qd)
}
//SetAncount
func (d DNS)SetAncount(an uint16){
//SetAncount
binary.BigEndian.PutUint16(d[ANCOUNT:] ,an)
}
//SetNscount
func (d DNS)SetNscount(ns uint16){
//SetNscount
binary.BigEndian.PutUint16(d[NSCOUNT:],ns)
//SetQAcount
binary.BigEndian.PutUint16(d[ARCOUNT:],qa)
}
//SetQAcount
func (d DNS)SetQAcount(qa uint16){
binary.BigEndian.PutUint16(d[QACOUNT:],qa)
//setID
func (d DNS)setID(id uint16){
//set id
binary.BigEndian.PutUint16(d[ID:], id)
}
//SetDomain
func (d *DNS)SetDomain(domain string) {
//setDomain
func (d *DNS)getDomain(domain string) []byte {
var (
buffer bytes.Buffer
segments []string = strings.Split(domain, ".")
)
binary.Write(&buffer,binary.BigEndian,*d)

for _, seg := range segments {
binary.Write(&buffer, binary.BigEndian, byte(len(seg)))
binary.Write(&buffer, binary.BigEndian, []byte(seg))
}
binary.Write(&buffer, binary.BigEndian, byte(0x00))

*d = buffer.Bytes()
//return buffer.Bytes()
return buffer.Bytes()
}
func (d *DNS)SetQuestion(qtype,qclass uint16){
//SetQuestion query field
//domain url
//qtype type
//qclass class
func (d *DNS)SetQuestion(domain string,qtype,qclass uint16){
for _,b := range d.getDomain(domain) {
*d = append((*d),b)
}
//d.setDomain(domain)
q := DNSQuestion{
QuestionType: qtype,
QuestionClass: qclass,
Expand Down
2 changes: 1 addition & 1 deletion protocol/transport/udp/client/write.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
tcpip "github.com/brewlin/net-protocol/protocol"
)
//Write
func (c *Client) Write(buf []byte) error {
func (c *Client) Write(buf []byte) *tcpip.Error {
v := buffer.View(buf)
for{
_,ch,err := c.ep.Write(tcpip.SlicePayload(v),
Expand Down

0 comments on commit 0c817c4

Please sign in to comment.