<commit_before>// Package xip provides functions to create a DNS server which, when queried
// with a hostname with an embedded IP address, returns that IP Address.  It
// was inspired by xip.io, which was created by <NAME>
package xip

import (
	"errors"
	"net"
	"regexp"
	"strings"

	"golang.org/x/net/dns/dnsmessage"
)

// https://stackoverflow.com/questions/53497/regular-expression-that-matches-valid-ipv6-addresses
var ipv4RE = regexp.MustCompile(`(^|[.-])(((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])[.-]){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))($|[.-])`)
var ipv6RE = regexp.MustCompile(`(^|[.-])(([0-9a-fA-F]{1,4}-){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}-){1,7}-|([0-9a-fA-F]{1,4}-){1,6}-[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}-){1,5}(-[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}-){1,4}(-[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}-){1,3}(-[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}-){1,2}(-[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}-((-[0-9a-fA-F]{1,4}){1,6})|-((-[0-9a-fA-F]{1,4}){1,7}|-)|fe80-(-[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|--(ffff(-0{1,4}){0,1}-){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}-){1,4}-((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))($|[.-])`)
var ErrNotFound = errors.New("record not found")

const (
	Hostmaster = "yoyo.nono.io."
	MxHost     = "mail.protonmail.ch."
)

// QueryResponse takes in a raw (packed) DNS query and returns a raw (packed)
// DNS response It takes in the raw data to offload as much as possible from
// main(). main() is hard to unit test, but functions like QueryResponse are
// easy.
func QueryResponse(queryBytes []byte) ([]byte, error) {
	var queryHeader dnsmessage.Header
	var err error
	var response []byte
	var p dnsmessage.Parser

	if queryHeader, err = p.Start(queryBytes); err != nil {
		return nil, err
	}

	b := dnsmessage.NewBuilder(response, ResponseHeader(queryHeader))
	b.EnableCompression()
	if err = b.StartQuestions(); err != nil {
		return nil, err
	}
	for {
		q, err := p.Question()
		if err == dnsmessage.ErrSectionDone {
			break
		}
		if err != nil {
			return nil, err
		}
		if err = b.Question(q); err != nil {
			return nil, err
		}
		switch q.Type {
		case dnsmessage.TypeA:
			{
				nameToA, err := NameToA(q.Name.String())
				if err != nil {
					// There's only one possible error this can be: ErrNotFound. note that
					// this could be written more efficiently; however, I wrote it to
					// accommodate 'if err != nil' convention. My first version was 'if
					// err == nil', and it flummoxed me.
					err = b.StartAuthorities()
					if err != nil {
						return nil, err
					}
					err = b.SOAResource(dnsmessage.ResourceHeader{
						Name:   q.Name,
						Type:   dnsmessage.TypeA,
						Class:  dnsmessage.ClassINET,
						TTL:    604800, // 60 * 60 * 24 * 7 == 1 week; it's not gonna change
						Length: 0,
					}, SOAResource(q.Name.String()))
					if err != nil {
						return nil, err
					}
				} else {
					err = b.StartAnswers()
					if err != nil {
						return nil, err
					}
					err = b.AResource(dnsmessage.ResourceHeader{
						Name:   q.Name,
						Type:   dnsmessage.TypeSOA,
						Class:  dnsmessage.ClassINET,
						TTL:    604800, // 60 * 60 * 24 * 7 == 1 week; long TTL, these IP addrs don't change
						Length: 0,
					}, *nameToA)
					if err != nil {
						panic(err.Error())
						return nil, err
					}
				}
			}
		case dnsmessage.TypeAAAA:
			{
				nameToAAAA, err := NameToAAAA(q.Name.String())
				if err != nil {
					// There's only one possible error this can be: ErrNotFound. note that
					// this could be written more efficiently; however, I wrote it to
					// accommodate 'if err != nil' convention. My first version was 'if
					// err == nil', and it flummoxed me.
					err = b.StartAuthorities()
					if err != nil {
						return nil, err
					}
					err = b.SOAResource(dnsmessage.ResourceHeader{
						Name:   q.Name,
						Type:   dnsmessage.TypeSOA,
						Class:  dnsmessage.ClassINET,
						TTL:    604800, // 60 * 60 * 24 * 7 == 1 week; it's not gonna change
						Length: 0,
					}, SOAResource(q.Name.String()))
					if err != nil {
						return nil, err
					}
				} else {
					err = b.StartAnswers()
					if err != nil {
						return nil, err
					}
					err = b.AAAAResource(dnsmessage.ResourceHeader{
						Name:   q.Name,
						Type:   dnsmessage.TypeAAAA,
						Class:  dnsmessage.ClassINET,
						TTL:    604800, // 60 * 60 * 24 * 7 == 1 week; long TTL, these IP addrs don't change
						Length: 0,
					}, *nameToAAAA)
					if err != nil {
						panic(err.Error())
						return nil, err
					}
				}
			}
		}
	}

	responseBytes, err := b.Finish()
	// I couldn't figure an easy way to test the error condition in Ginkgo
	if err != nil {
		return nil, err
	}
	return responseBytes, nil
}

// ResponseHeader returns a pre-fab DNS response header. Note that we're always
// authoritative and therefore recursion is never available.  We're able to
// "white label" domains by indiscriminately matching every query that comes
// our way. Not being recursive has the added benefit of not being usable as an
// amplifier in a DDOS attack
func ResponseHeader(query dnsmessage.Header) dnsmessage.Header {
	return dnsmessage.Header{
		ID:                 query.ID,
		Response:           true,
		OpCode:             0,
		Authoritative:      true,
		Truncated:          false,
		RecursionDesired:   query.RecursionDesired,
		RecursionAvailable: false,
	}
}

// NameToA returns either an AResource that matched the hostname or ErrNotFound
func NameToA(fqdnString string) (*dnsmessage.AResource, error) {
	fqdn := []byte(fqdnString)
	if !ipv4RE.Match(fqdn) {
		return &dnsmessage.AResource{}, ErrNotFound
	}

	match := string(ipv4RE.FindSubmatch(fqdn)[2])
	match = strings.Replace(match, "-", ".", -1)
	ipv4address := net.ParseIP(match).To4()

	return &dnsmessage.AResource{A: [4]byte{ipv4address[0], ipv4address[1], ipv4address[2], ipv4address[3]}}, nil
}

// NameToAAAA NameToA returns either an AAAAResource that matched the hostname
// or ErrNotFound
func NameToAAAA(fqdnString string) (*dnsmessage.AAAAResource, error) {
	fqdn := []byte(fqdnString)
	if !ipv6RE.Match(fqdn) {
		return &dnsmessage.AAAAResource{}, ErrNotFound
	}

	match := string(ipv6RE.FindSubmatch(fqdn)[2])
	match = strings.Replace(match, "-", ":", -1)
	ipv16address := net.ParseIP(match).To16()

	AAAAR := dnsmessage.AAAAResource{}
	for i := range ipv16address {
		AAAAR.AAAA[i] = ipv16address[i]
	}
	return &AAAAR, nil
}

// SOAResource returns the hard-coded SOA
func SOAResource(domain string) dnsmessage.SOAResource {
	var domainArray [255]byte
	copy(domainArray[:], domain)
	var mboxArray [255]byte
	copy(mboxArray[:], Hostmaster)
	return dnsmessage.SOAResource{
		NS: dnsmessage.Name{
			Data:   domainArray,
			Length: uint8(len(domain)),
		},
		MBox: dnsmessage.Name{
			Data:   mboxArray,
			Length: uint8(len(Hostmaster)),
		},
		Serial: 2020090400,
		// I cribbed the Refresh/Retry/Expire from google.com
		Refresh: 900,
		Retry:   900,
		Expire:  1800,
		MinTTL:  300,
	}
}

func MXResource() dnsmessage.MXResource {
	var mxHostBytes [255]byte
	copy(mxHostBytes[:], MxHost)
	return dnsmessage.MXResource{
		Pref: 0,
		MX: dnsmessage.Name{
			Data:   mxHostBytes,
			Length: uint8(len(MxHost)),
		},
	}
}
<commit_msg>Extracted method `processQuestion()`<commit_after>// Package xip provides functions to create a DNS server which, when queried
// with a hostname with an embedded IP address, returns that IP Address.  It
// was inspired by xip.io, which was created by <NAME>
package xip

import (
	"errors"
	"net"
	"regexp"
	"strings"

	"golang.org/x/net/dns/dnsmessage"
)

// https://stackoverflow.com/questions/53497/regular-expression-that-matches-valid-ipv6-addresses
var ipv4RE = regexp.MustCompile(`(^|[.-])(((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])[.-]){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))($|[.-])`)
var ipv6RE = regexp.MustCompile(`(^|[.-])(([0-9a-fA-F]{1,4}-){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}-){1,7}-|([0-9a-fA-F]{1,4}-){1,6}-[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}-){1,5}(-[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}-){1,4}(-[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}-){1,3}(-[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}-){1,2}(-[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}-((-[0-9a-fA-F]{1,4}){1,6})|-((-[0-9a-fA-F]{1,4}){1,7}|-)|fe80-(-[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|--(ffff(-0{1,4}){0,1}-){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}-){1,4}-((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))($|[.-])`)
var ErrNotFound = errors.New("record not found")

const (
	Hostmaster = "yoyo.nono.io."
	MxHost     = "mail.protonmail.ch."
)

// QueryResponse takes in a raw (packed) DNS query and returns a raw (packed)
// DNS response It takes in the raw data to offload as much as possible from
// main(). main() is hard to unit test, but functions like QueryResponse are
// easy.
func QueryResponse(queryBytes []byte) ([]byte, error) {
	var queryHeader dnsmessage.Header
	var err error
	var response []byte
	var p dnsmessage.Parser

	if queryHeader, err = p.Start(queryBytes); err != nil {
		return nil, err
	}

	b := dnsmessage.NewBuilder(response, ResponseHeader(queryHeader))
	b.EnableCompression()
	if err = b.StartQuestions(); err != nil {
		return nil, err
	}
	for {
		q, err := p.Question()
		if err == dnsmessage.ErrSectionDone {
			break
		}
		if err != nil {
			return nil, err
		}
		if err = b.Question(q); err != nil {
			return nil, err
		}
		err = processQuestion(q, &b)
		if err != nil {
			return nil, err
		}
	}

	responseBytes, err := b.Finish()
	// I couldn't figure an easy way to test the error condition in Ginkgo
	if err != nil {
		return nil, err
	}
	return responseBytes, nil
}

func processQuestion(q dnsmessage.Question, b *dnsmessage.Builder) error {
	switch q.Type {
	case dnsmessage.TypeA:
		{
			nameToA, err := NameToA(q.Name.String())
			if err != nil {
				// There's only one possible error this can be: ErrNotFound. note that
				// this could be written more efficiently; however, I wrote it to
				// accommodate 'if err != nil' convention. My first version was 'if
				// err == nil', and it flummoxed me.
				err = b.StartAuthorities()
				if err != nil {
					return err
				}
				err = b.SOAResource(dnsmessage.ResourceHeader{
					Name:   q.Name,
					Type:   dnsmessage.TypeA,
					Class:  dnsmessage.ClassINET,
					TTL:    604800, // 60 * 60 * 24 * 7 == 1 week; it's not gonna change
					Length: 0,
				}, SOAResource(q.Name.String()))
				if err != nil {
					return err
				}
			} else {
				err = b.StartAnswers()
				if err != nil {
					return err
				}
				err = b.AResource(dnsmessage.ResourceHeader{
					Name:   q.Name,
					Type:   dnsmessage.TypeSOA,
					Class:  dnsmessage.ClassINET,
					TTL:    604800, // 60 * 60 * 24 * 7 == 1 week; long TTL, these IP addrs don't change
					Length: 0,
				}, *nameToA)
				if err != nil {
					panic(err.Error())
					return err
				}
			}
		}
	case dnsmessage.TypeAAAA:
		{
			nameToAAAA, err := NameToAAAA(q.Name.String())
			if err != nil {
				// There's only one possible error this can be: ErrNotFound. note that
				// this could be written more efficiently; however, I wrote it to
				// accommodate 'if err != nil' convention. My first version was 'if
				// err == nil', and it flummoxed me.
				err = b.StartAuthorities()
				if err != nil {
					return err
				}
				err = b.SOAResource(dnsmessage.ResourceHeader{
					Name:   q.Name,
					Type:   dnsmessage.TypeSOA,
					Class:  dnsmessage.ClassINET,
					TTL:    604800, // 60 * 60 * 24 * 7 == 1 week; it's not gonna change
					Length: 0,
				}, SOAResource(q.Name.String()))
				if err != nil {
					return err
				}
			} else {
				err = b.StartAnswers()
				if err != nil {
					return err
				}
				err = b.AAAAResource(dnsmessage.ResourceHeader{
					Name:   q.Name,
					Type:   dnsmessage.TypeAAAA,
					Class:  dnsmessage.ClassINET,
					TTL:    604800, // 60 * 60 * 24 * 7 == 1 week; long TTL, these IP addrs don't change
					Length: 0,
				}, *nameToAAAA)
				if err != nil {
					panic(err.Error())
					return err
				}
			}
		}
	}
	return nil
}

// ResponseHeader returns a pre-fab DNS response header. Note that we're always
// authoritative and therefore recursion is never available.  We're able to
// "white label" domains by indiscriminately matching every query that comes
// our way. Not being recursive has the added benefit of not being usable as an
// amplifier in a DDOS attack
func ResponseHeader(query dnsmessage.Header) dnsmessage.Header {
	return dnsmessage.Header{
		ID:                 query.ID,
		Response:           true,
		OpCode:             0,
		Authoritative:      true,
		Truncated:          false,
		RecursionDesired:   query.RecursionDesired,
		RecursionAvailable: false,
	}
}

// NameToA returns either an AResource that matched the hostname or ErrNotFound
func NameToA(fqdnString string) (*dnsmessage.AResource, error) {
	fqdn := []byte(fqdnString)
	if !ipv4RE.Match(fqdn) {
		return &dnsmessage.AResource{}, ErrNotFound
	}

	match := string(ipv4RE.FindSubmatch(fqdn)[2])
	match = strings.Replace(match, "-", ".", -1)
	ipv4address := net.ParseIP(match).To4()

	return &dnsmessage.AResource{A: [4]byte{ipv4address[0], ipv4address[1], ipv4address[2], ipv4address[3]}}, nil
}

// NameToAAAA NameToA returns either an AAAAResource that matched the hostname
// or ErrNotFound
func NameToAAAA(fqdnString string) (*dnsmessage.AAAAResource, error) {
	fqdn := []byte(fqdnString)
	if !ipv6RE.Match(fqdn) {
		return &dnsmessage.AAAAResource{}, ErrNotFound
	}

	match := string(ipv6RE.FindSubmatch(fqdn)[2])
	match = strings.Replace(match, "-", ":", -1)
	ipv16address := net.ParseIP(match).To16()

	AAAAR := dnsmessage.AAAAResource{}
	for i := range ipv16address {
		AAAAR.AAAA[i] = ipv16address[i]
	}
	return &AAAAR, nil
}

// SOAResource returns the hard-coded SOA
func SOAResource(domain string) dnsmessage.SOAResource {
	var domainArray [255]byte
	copy(domainArray[:], domain)
	var mboxArray [255]byte
	copy(mboxArray[:], Hostmaster)
	return dnsmessage.SOAResource{
		NS: dnsmessage.Name{
			Data:   domainArray,
			Length: uint8(len(domain)),
		},
		MBox: dnsmessage.Name{
			Data:   mboxArray,
			Length: uint8(len(Hostmaster)),
		},
		Serial: 2020090400,
		// I cribbed the Refresh/Retry/Expire from google.com
		Refresh: 900,
		Retry:   900,
		Expire:  1800,
		MinTTL:  300,
	}
}

func MXResource() dnsmessage.MXResource {
	var mxHostBytes [255]byte
	copy(mxHostBytes[:], MxHost)
	return dnsmessage.MXResource{
		Pref: 0,
		MX: dnsmessage.Name{
			Data:   mxHostBytes,
			Length: uint8(len(MxHost)),
		},
	}
}

{'fraction_non_alphanumeric': 0.17248153919111173, 'fraction_numerical': 0.047151277013752456, 'mean_word_length': 3.117712691771269, 'pattern_counts': {'":': 2, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1147795', 'n_tokens_mistral': 6776, 'n_tokens_neox': 5829, 'n_words': 1325}