mirror of
https://github.com/cunnie/sslip.io.git
synced 2025-10-07 08:31:02 +08:00
Use dnsmessage
's Parser() and
Builder()`
- Change Ginkgo's `To(Not(` to use the shorter `ToNot(` - did fewer initializations in the `vars` block and moved them to the `BeforeEach()` blocks. The `QueryResponse()` test is too long & convoluted; even I have a hard time understanding them, and I wrote them! The tests & code should be re-written, but that's for another day.
This commit is contained in:
@@ -25,14 +25,17 @@ func QueryResponse(queryBytes []byte) ([]byte, error) {
|
|||||||
var queryHeader dnsmessage.Header
|
var queryHeader dnsmessage.Header
|
||||||
var err error
|
var err error
|
||||||
var response []byte
|
var response []byte
|
||||||
|
var p dnsmessage.Parser
|
||||||
|
|
||||||
p := dnsmessage.Parser{}
|
|
||||||
if queryHeader, err = p.Start(queryBytes); err != nil {
|
if queryHeader, err = p.Start(queryBytes); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
b := dnsmessage.NewBuilder(response, ResponseHeader(queryHeader))
|
b := dnsmessage.NewBuilder(response, ResponseHeader(queryHeader))
|
||||||
b.EnableCompression()
|
b.EnableCompression()
|
||||||
|
if err = b.StartQuestions(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
for {
|
for {
|
||||||
q, err := p.Question()
|
q, err := p.Question()
|
||||||
if err == dnsmessage.ErrSectionDone {
|
if err == dnsmessage.ErrSectionDone {
|
||||||
@@ -41,6 +44,9 @@ func QueryResponse(queryBytes []byte) ([]byte, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if err = b.Question(q); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
switch q.Type {
|
switch q.Type {
|
||||||
case dnsmessage.TypeA:
|
case dnsmessage.TypeA:
|
||||||
{
|
{
|
||||||
@@ -73,7 +79,7 @@ func QueryResponse(queryBytes []byte) ([]byte, error) {
|
|||||||
Name: q.Name,
|
Name: q.Name,
|
||||||
Type: dnsmessage.TypeA,
|
Type: dnsmessage.TypeA,
|
||||||
Class: dnsmessage.ClassINET,
|
Class: dnsmessage.ClassINET,
|
||||||
TTL: 604800, // 60 * 60 * 24 * 7 == 1 week; it's not gonna change
|
TTL: 604800, // 60 * 60 * 24 * 7 == 1 week; long TTL, these IP addrs don't change
|
||||||
Length: 0,
|
Length: 0,
|
||||||
}, *nameToA)
|
}, *nameToA)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -86,7 +92,7 @@ func QueryResponse(queryBytes []byte) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
responseBytes, err := b.Finish()
|
responseBytes, err := b.Finish()
|
||||||
// I couldn't figure an easy way to test the error condition in Ginkgo. Sue me.
|
// I couldn't figure an easy way to test the error condition in Ginkgo
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -137,7 +143,7 @@ func NameToAAAA(fqdnString string) (*dnsmessage.AAAAResource, error) {
|
|||||||
ipv16address := net.ParseIP(match).To16()
|
ipv16address := net.ParseIP(match).To16()
|
||||||
|
|
||||||
AAAAR := dnsmessage.AAAAResource{}
|
AAAAR := dnsmessage.AAAAResource{}
|
||||||
for i, _ := range ipv16address {
|
for i := range ipv16address {
|
||||||
AAAAR.AAAA[i] = ipv16address[i]
|
AAAAR.AAAA[i] = ipv16address[i]
|
||||||
}
|
}
|
||||||
return &AAAAR, nil
|
return &AAAAR, nil
|
||||||
|
@@ -13,27 +13,26 @@ import (
|
|||||||
var _ = Describe("Xip", func() {
|
var _ = Describe("Xip", func() {
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
name = "127.0.0.1.sslip.io."
|
queryBuilder dnsmessage.Builder
|
||||||
|
name string
|
||||||
nameArray [255]byte
|
nameArray [255]byte
|
||||||
packedQuery []byte
|
packedQuery []byte
|
||||||
packedResponse []byte
|
packedResponse []byte
|
||||||
response dnsmessage.Message
|
response dnsmessage.Message
|
||||||
|
expectedResponse dnsmessage.Message
|
||||||
headerId uint16
|
headerId uint16
|
||||||
query = dnsmessage.Message{
|
question dnsmessage.Question
|
||||||
Header: dnsmessage.Header{
|
)
|
||||||
ID: headerId,
|
Describe("QueryResponse()", func() {
|
||||||
RecursionDesired: true,
|
BeforeEach(func() {
|
||||||
},
|
name = "127.0.0.1.sslip.io."
|
||||||
Questions: []dnsmessage.Question{
|
copy(nameArray[:], name)
|
||||||
{
|
// Set the query's header ID
|
||||||
|
headerId = uint16(rand.Int31())
|
||||||
|
question = dnsmessage.Question{
|
||||||
Name: dnsmessage.Name{Length: uint8(len(name)), Data: nameArray},
|
Name: dnsmessage.Name{Length: uint8(len(name)), Data: nameArray},
|
||||||
Type: dnsmessage.TypeA,
|
Type: dnsmessage.TypeA,
|
||||||
Class: dnsmessage.ClassINET,
|
Class: dnsmessage.ClassINET,
|
||||||
},
|
|
||||||
},
|
|
||||||
Answers: nil,
|
|
||||||
Authorities: nil,
|
|
||||||
Additionals: nil,
|
|
||||||
}
|
}
|
||||||
expectedResponse = dnsmessage.Message{
|
expectedResponse = dnsmessage.Message{
|
||||||
Header: dnsmessage.Header{
|
Header: dnsmessage.Header{
|
||||||
@@ -48,43 +47,64 @@ var _ = Describe("Xip", func() {
|
|||||||
Answers: []dnsmessage.Resource{
|
Answers: []dnsmessage.Resource{
|
||||||
{
|
{
|
||||||
Header: dnsmessage.ResourceHeader{
|
Header: dnsmessage.ResourceHeader{
|
||||||
Name: query.Questions[0].Name,
|
Name: question.Name,
|
||||||
Type: dnsmessage.TypeA,
|
Type: dnsmessage.TypeA,
|
||||||
Class: dnsmessage.ClassINET,
|
Class: dnsmessage.ClassINET,
|
||||||
TTL: 300,
|
TTL: 604800,
|
||||||
Length: 4,
|
Length: 4,
|
||||||
},
|
},
|
||||||
Body: &dnsmessage.AResource{A: [4]byte{127, 0, 0, 1}},
|
Body: &dnsmessage.AResource{A: [4]byte{127, 0, 0, 1}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Authorities: []dnsmessage.Resource{},
|
Authorities: []dnsmessage.Resource{},
|
||||||
// {
|
|
||||||
// Header: dnsmessage.ResourceHeader{},
|
|
||||||
// Body: xip.SOAResource(name),
|
|
||||||
// },
|
|
||||||
//},
|
|
||||||
Additionals: []dnsmessage.Resource{},
|
Additionals: []dnsmessage.Resource{},
|
||||||
}
|
}
|
||||||
)
|
|
||||||
Describe("QueryResponse()", func() {
|
|
||||||
BeforeEach(func() {
|
|
||||||
headerId = uint16(rand.Int31())
|
|
||||||
})
|
})
|
||||||
JustBeforeEach(func() {
|
JustBeforeEach(func() {
|
||||||
|
// Warning: this JustBeforeEach is way too long; I know.
|
||||||
// Initializing query.Questions _should_ be above, in the `var` section, but there's
|
// Initializing query.Questions _should_ be above, in the `var` section, but there's
|
||||||
// no readable way to initialize Data ([255]byte); `copy()`, however, is readable
|
// no readable way to initialize Data ([255]byte); `copy()`, however, is readable
|
||||||
copy(nameArray[:], name)
|
|
||||||
query.Questions[0].Name = dnsmessage.Name{Length: uint8(len(name)), Data: nameArray}
|
// Set up the DNS query
|
||||||
query.ID = headerId
|
queryBuilder = dnsmessage.NewBuilder(nil, dnsmessage.Header{
|
||||||
|
ID: headerId,
|
||||||
|
Response: false,
|
||||||
|
OpCode: 0,
|
||||||
|
Authoritative: false,
|
||||||
|
Truncated: false,
|
||||||
|
RecursionDesired: true,
|
||||||
|
RecursionAvailable: false,
|
||||||
|
RCode: 0,
|
||||||
|
})
|
||||||
|
queryBuilder.EnableCompression()
|
||||||
|
question := dnsmessage.Question{
|
||||||
|
Name: dnsmessage.Name{
|
||||||
|
Data: nameArray,
|
||||||
|
Length: uint8(len(name)),
|
||||||
|
},
|
||||||
|
Type: dnsmessage.TypeA,
|
||||||
|
Class: dnsmessage.ClassINET,
|
||||||
|
}
|
||||||
|
err = queryBuilder.StartQuestions()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
err = queryBuilder.Question(question)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
packedQuery, err = queryBuilder.Finish()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
var deleteMe dnsmessage.Message
|
||||||
|
err = deleteMe.Unpack(packedQuery)
|
||||||
|
|
||||||
|
// Put the finishing touches on the expected response
|
||||||
expectedResponse.ID = headerId
|
expectedResponse.ID = headerId
|
||||||
expectedResponse.Questions = query.Questions
|
expectedResponse.Questions = append(expectedResponse.Questions, question)
|
||||||
expectedResponse.Answers[0].Header.Name = query.Questions[0].Name
|
expectedResponse.Answers[0].Header.Name = question.Name
|
||||||
packedQuery, err = query.Pack()
|
|
||||||
Expect(err).To(Not(HaveOccurred()))
|
// The heart of the code: call QueryResponse()
|
||||||
packedResponse, err = xip.QueryResponse(packedQuery)
|
packedResponse, err = xip.QueryResponse(packedQuery)
|
||||||
Expect(err).To(Not(HaveOccurred()))
|
Expect(err).ToNot(HaveOccurred())
|
||||||
err = response.Unpack(packedResponse)
|
err = response.Unpack(packedResponse)
|
||||||
Expect(err).To(Not(HaveOccurred()))
|
Expect(err).ToNot(HaveOccurred())
|
||||||
})
|
})
|
||||||
When("It cannot Unpack() the query", func() {
|
When("It cannot Unpack() the query", func() {
|
||||||
It("returns an error", func() {
|
It("returns an error", func() {
|
||||||
@@ -95,31 +115,69 @@ var _ = Describe("Xip", func() {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
It("should return the correct expectedResponse", func() {
|
It("should return the correct expectedResponse", func() {
|
||||||
Expect(err).To(Not(HaveOccurred()))
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
// break the sections out to make debugging easier
|
||||||
|
Expect(response.Header).To(Equal(expectedResponse.Header))
|
||||||
|
Expect(response.Questions).To(Equal(expectedResponse.Questions))
|
||||||
|
Expect(response.Answers).To(Equal(expectedResponse.Answers))
|
||||||
|
Expect(response.Authorities).To(Equal(expectedResponse.Authorities))
|
||||||
|
Expect(response.Additionals).To(Equal(expectedResponse.Additionals))
|
||||||
|
// and now the whole enchilada
|
||||||
Expect(response).To(Equal(expectedResponse))
|
Expect(response).To(Equal(expectedResponse))
|
||||||
})
|
})
|
||||||
When("There is A record cannot be found", func() {
|
When("an A record cannot be found", func() {
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
name = "not-an-ip.sslip.io."
|
name = "not-an-ip.sslip.io."
|
||||||
|
copy(nameArray[:], name)
|
||||||
|
expectedSOA := xip.SOAResource(name)
|
||||||
|
expectedAuthority := dnsmessage.Resource{
|
||||||
|
Header: dnsmessage.ResourceHeader{
|
||||||
|
Name: dnsmessage.Name{
|
||||||
|
Data: nameArray,
|
||||||
|
Length: uint8(len(name)),
|
||||||
|
},
|
||||||
|
Type: dnsmessage.TypeSOA,
|
||||||
|
Class: dnsmessage.ClassINET,
|
||||||
|
TTL: 604800,
|
||||||
|
Length: 45,
|
||||||
|
},
|
||||||
|
Body: &expectedSOA,
|
||||||
|
}
|
||||||
|
expectedResponse.Authorities = append(expectedResponse.Authorities, expectedAuthority)
|
||||||
})
|
})
|
||||||
It("returns the no answers, but returns an authoritative section", func() {
|
It("returns the no answers, but returns an authoritative section", func() {
|
||||||
Expect(err).To(Not(HaveOccurred()))
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(response.Answers).To(Equal([]dnsmessage.Resource{}))
|
Expect(response.Answers).To(Equal([]dnsmessage.Resource{}))
|
||||||
Expect(response.Authorities).To(Equal(xip.SOAResource(name)))
|
// break test down for easier debugging
|
||||||
|
Expect(len(response.Answers)).To(Equal(0))
|
||||||
|
Expect(len(response.Authorities)).To(Equal(1))
|
||||||
|
Expect(response.Authorities[0].Header.Name).To(Equal(expectedResponse.Authorities[0].Header.Name))
|
||||||
|
Expect(response.Authorities[0].Header).To(Equal(expectedResponse.Authorities[0].Header))
|
||||||
|
Expect(response.Authorities[0].Body).To(Equal(expectedResponse.Authorities[0].Body))
|
||||||
|
Expect(response.Authorities[0]).To(Equal(expectedResponse.Authorities[0]))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
Describe("ResponseHeader()", func() {
|
Describe("ResponseHeader()", func() {
|
||||||
It("returns a header with the ID", func() {
|
It("returns a header with the ID", func() {
|
||||||
query.ID = uint16(rand.Int31())
|
headerId = uint16(rand.Int31())
|
||||||
Expect(xip.ResponseHeader(query.Header)).To(Equal(dnsmessage.Header{
|
Expect(xip.ResponseHeader(dnsmessage.Header{
|
||||||
ID: query.ID,
|
ID: headerId,
|
||||||
|
Response: false,
|
||||||
|
OpCode: 0,
|
||||||
|
Authoritative: false,
|
||||||
|
Truncated: false,
|
||||||
|
RecursionDesired: false,
|
||||||
|
RecursionAvailable: false,
|
||||||
|
RCode: 0,
|
||||||
|
})).To(Equal(dnsmessage.Header{
|
||||||
|
ID: headerId, // taken from the query
|
||||||
Response: true,
|
Response: true,
|
||||||
OpCode: 0,
|
OpCode: 0,
|
||||||
Authoritative: true,
|
Authoritative: true,
|
||||||
Truncated: false,
|
Truncated: false,
|
||||||
RecursionDesired: query.RecursionDesired,
|
RecursionDesired: false, // taken from the query
|
||||||
RecursionAvailable: false,
|
RecursionAvailable: false,
|
||||||
RCode: 0,
|
RCode: 0,
|
||||||
}))
|
}))
|
||||||
@@ -130,7 +188,7 @@ var _ = Describe("Xip", func() {
|
|||||||
DescribeTable("when it succeeds",
|
DescribeTable("when it succeeds",
|
||||||
func(fqdn string, expectedA dnsmessage.AResource) {
|
func(fqdn string, expectedA dnsmessage.AResource) {
|
||||||
ipv4Answer, err := xip.NameToA(fqdn)
|
ipv4Answer, err := xip.NameToA(fqdn)
|
||||||
Expect(err).To(Not(HaveOccurred()))
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(*ipv4Answer).To(Equal(expectedA))
|
Expect(*ipv4Answer).To(Equal(expectedA))
|
||||||
},
|
},
|
||||||
// dots
|
// dots
|
||||||
@@ -163,7 +221,7 @@ var _ = Describe("Xip", func() {
|
|||||||
DescribeTable("when it succeeds",
|
DescribeTable("when it succeeds",
|
||||||
func(fqdn string, expectedAAAA dnsmessage.AAAAResource) {
|
func(fqdn string, expectedAAAA dnsmessage.AAAAResource) {
|
||||||
ipv6Answer, err := xip.NameToAAAA(fqdn)
|
ipv6Answer, err := xip.NameToAAAA(fqdn)
|
||||||
Expect(err).To(Not(HaveOccurred()))
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(*ipv6Answer).To(Equal(expectedAAAA))
|
Expect(*ipv6Answer).To(Equal(expectedAAAA))
|
||||||
},
|
},
|
||||||
// dashes only
|
// dashes only
|
||||||
|
Reference in New Issue
Block a user