예제 #1
0
func unpackRR(data []byte, index int) (rr RR, offset int, err error) {
	offset = index
	var hdr RRHeader
	hdr.Name, offset, err = UnpackDomainName(data, offset, MAX_COMPRESSION_DEPTH)
	if err != nil {
		return
	}
	if offset+10 > len(data) {
		err = errors.New("out of range")
		return
	}
	hdr.Type, offset = UnPackUint16(data, offset)
	hdr.Class, offset = UnPackUint16(data, offset)
	hdr.Ttl, offset = UnPackUint32(data, offset)
	hdr.RDLength, offset = UnPackUint16(data, offset)

	if hdr.Class != CLASS_INET {
		err = errors.New("unimplement")
		return
	}

	rr, err = RRNew(hdr.Type)
	if err != nil {
		return
	}
	rr.SetHeader(&hdr)
	offset, err = rr.UnpackRData(data, offset)
	return
}
예제 #2
0
func PackDomainName(name string, buf []byte, index int, compression map[string]int) (offset int, err error) {
	bufLen := len(buf)
	offset = index
	if len(name) > MAX_DOMAIN_NAME_LEN {
		err = errors.New(fmt.Sprintf("Domain name length must <= %d: %s", MAX_DOMAIN_NAME_LEN, name))
		return
	}
	tempName := name
	for {
		if len(tempName) == 0 {
			break
		}
		if compression != nil {
			//need compress
			if ptr, ok := compression[tempName]; ok {
				offset = PackUint16(uint16(ptr), buf, offset)
				buf[offset-2] |= 0xC0
				return
			}
		}
		dotIndex := strings.Index(tempName, ".")
		var label string
		if dotIndex == -1 {
			label = tempName
			tempName = ""
		} else {
			label = tempName[:dotIndex]
			tempName = tempName[dotIndex+1:]
		}
		labelLen := len(label)
		if labelLen > MAX_DOMAIN_LABEL_LEN {
			err = errors.New(fmt.Sprintf("Domain label length must <= %d: %s", MAX_DOMAIN_LABEL_LEN, label))
			return
		}
		if labelLen+1 > bufLen-offset {
			err = errors.New("buffer too small to store " + name)
			return
		}
		if compression != nil {
			compression[label+"."+tempName] = offset
		}
		buf[offset] = uint8(labelLen)
		offset++
		copy(buf[offset:], label)
		offset += labelLen
	}
	buf[offset] = 0
	offset++
	return
}
예제 #3
0
파일: rr_mx.go 프로젝트: public0821/gotemp
func (m *RRMx) SetRData(data string) (err error) {
	fields := strings.Split(data, " ")
	if len(fields) != 2 {
		err = errors.New("invalid mx rdata: " + data)
		return
	}
	m.domain = fields[0]
	priority, err := strconv.Atoi(fields[1])
	if err != nil {
		err = errors.New("invalid mx priority: " + fields[1])
		return
	}
	m.priority = uint16(priority)
	return
}
예제 #4
0
func (msg *Message) UnpackAll(data []byte) (err error) {
	var offset int
	offset, err = msg.UnpackHeaderAndQuestion(data)
	if err != nil {
		return
	}
	msg.Answer = make([]RR, msg.Hdr.ANCount)
	msg.Authority = make([]RR, msg.Hdr.NSCount)
	msg.Additional = make([]RR, msg.Hdr.ARCount)

	for i := uint16(0); i < msg.Hdr.ANCount; i++ {
		msg.Answer[i], offset, err = unpackRR(data, offset)
		if err != nil {
			return
		}
	}
	for i := uint16(0); i < msg.Hdr.NSCount; i++ {
		msg.Authority[i], offset, err = unpackRR(data, offset)
		if err != nil {
			return
		}
	}
	for i := uint16(0); i < msg.Hdr.ARCount; i++ {
		msg.Additional[i], offset, err = unpackRR(data, offset)
		if err != nil {
			return
		}
	}
	if offset != len(data) {
		err = errors.New("message data too long")
		return
	}
	return nil
}
예제 #5
0
// Unpack a binary message to a Msg structure.
func (msg *Message) UnpackHeaderAndQuestion(data []byte) (offset int, err error) {
	if len(data) < HEADER_LENGTH {
		err = errors.New("message data too short")
		return
	}

	//unpack message hearder
	offset = 0
	msg.Hdr.Id, offset = UnPackUint16(data, offset)
	msg.Hdr.QueryResponse = (uint8(data[offset]) & _QUREY_RESPONSE) >> 7
	msg.Hdr.Opcode = (uint8(data[offset]) & _OPCODE) >> 3
	msg.Hdr.AuthAnswer = uint8(data[offset])&_AUTH_ANSWER != 0
	msg.Hdr.Truncated = uint8(data[offset])&_TRUNCATED != 0
	msg.Hdr.RecursionDesired = uint8(data[offset])&_RECURSION_DESIRED != 0
	offset += 1
	msg.Hdr.RecursionAvailable = uint8(data[offset])&_RECURSION_AVAILABLE != 0
	msg.Hdr.Zero = (uint8(data[offset]) & _ZERO) >> 4
	msg.Hdr.Rcode = uint8(data[offset]) & _RCODE
	offset += 1
	msg.Hdr.QDCount, offset = UnPackUint16(data, offset)
	msg.Hdr.ANCount, offset = UnPackUint16(data, offset)
	msg.Hdr.NSCount, offset = UnPackUint16(data, offset)
	msg.Hdr.ARCount, offset = UnPackUint16(data, offset)

	// Arrays.
	msg.Question = make([]Question, msg.Hdr.QDCount)

	for i := uint16(0); i < msg.Hdr.QDCount; i++ {
		offset, err = unpackQuestion(data, offset, &msg.Question[i])
		if err != nil {
			return
		}
	}
	return
}
예제 #6
0
func (a *RRAaaa) SetRData(data string) (err error) {
	a.IPv6 = net.ParseIP(data)
	if a.IPv6 == nil {
		err = errors.New("malformed ipv6 address: " + data)
	}
	return
}
예제 #7
0
func (a *RRAaaa) UnpackRData(buf []byte, index int) (offset int, err error) {
	offset = index
	if len(buf)-offset < net.IPv6len {
		err = errors.New("data too short")
		return
	}
	copy(a.IPv6, buf[offset:offset+16])
	offset += net.IPv6len
	return
}
예제 #8
0
파일: rr.go 프로젝트: public0821/gotemp
func (a *RRA) UnpackRData(buf []byte, index int) (offset int, err error) {
	offset = index
	if len(buf)-offset < net.IPv4len {
		err = errors.New("data too short")
		return
	}
	a.IPv4 = net.IPv4(buf[offset], buf[offset+1], buf[offset+2], buf[offset+3])
	offset += net.IPv4len
	return
}
예제 #9
0
func UnpackDomainName(data []byte, index int, maxDepth int) (name string, offset int, err error) {
	dataLen := len(data)
	offset = index
	for {
		if offset+1 > dataLen {
			err = errors.New("out of range")
			return
		}
		labelLen := int(data[offset])
		offset++
		switch uint8(labelLen) & 0xC0 {
		case 0x00:
			// end of name
			if labelLen == 0x00 {
				if len(name) == 0 {
					name = "."
					return
				} else {
					//remove the last dot
					name = name[:len(name)-1]
					return
				}
			}
			if offset+labelLen > dataLen {
				err = errors.New("out of range")
				return
			}
			name += string(data[offset : offset+labelLen])
			name += "."
			offset += labelLen
		case 0xC0:
			if offset+1 > dataLen {
				err = errors.New("out of range")
				return
			}
			lablePtr := uint16(data[offset-1])<<10>>2 | uint16(data[offset])
			offset++
			// pointer to somewhere else in message.
			if int(lablePtr) > dataLen {
				err = errors.New("ptr out of range")
				return
			}
			if maxDepth == 0 {
				err = errors.New("too many ptr")
				return
			}
			tempName, _, tempErr := UnpackDomainName(data, int(lablePtr), maxDepth-1)
			if tempErr != nil {
				return
			}
			name += tempName
			return
		default:
			// 0x80 and 0x40 are reserved
			err = errors.New("fomart error")
			return
		}
	}
	return
}
예제 #10
0
func packQuestion(buf []byte, index int, question *Question, compression map[string]int) (offset int, err error) {
	offset, err = PackDomainName(question.Name, buf, index, compression)
	if err != nil {
		return
	}
	if 4 > len(buf)-offset {
		err = errors.New("buffer too small to store question type and class")
		return
	}
	offset = PackUint16(question.Type, buf, offset)
	offset = PackUint16(question.Class, buf, offset)
	return
}
예제 #11
0
파일: rr_mx.go 프로젝트: public0821/gotemp
func (m *RRMx) PackRData(buf []byte, index int) (offset int, err error) {
	offset = index
	if len(buf) < offset+2 {
		err = errors.New("buf too short")
		return
	}
	offset = PackUint16(m.priority, buf, offset)
	offset, err = PackDomainName(m.domain, buf, offset, nil)
	if err != nil {
		return
	}
	return
}
예제 #12
0
func unpackQuestion(data []byte, index int, question *Question) (offset int, err error) {
	offset = index
	question.Name, offset, err = UnpackDomainName(data, offset, MAX_COMPRESSION_DEPTH)
	if err != nil {
		return
	}
	if offset+4 > len(data) {
		err = errors.New("out of range")
		return
	}
	question.Type, offset = UnPackUint16(data, offset)
	question.Class, offset = UnPackUint16(data, offset)
	return
}
예제 #13
0
파일: rr.go 프로젝트: public0821/gotemp
func RRNew(rrtype uint16) (rr RR, err error) {
	switch rrtype {
	case TYPE_A:
		rr = new(RRA)
		return
	case TYPE_MX:
		rr = new(RRMx)
		return
	case TYPE_AAAA:
		rr = new(RRAaaa)
		return
	default:
		err = errors.New("unimplement")
		return
	}
}
예제 #14
0
func packRR(rr RR, buf []byte, index int, compression map[string]int) (offset int, err error) {
	offset = index
	header := rr.Header()
	offset, err = PackDomainName(header.Name, buf, offset, compression)
	if err != nil {
		return
	}
	//10 = sizeof(Type)+sizeof(Class)+sizeof(Ttl)+sizeof(RDLength)
	if 10 > len(buf)-offset {
		err = errors.New("buffer too small to store RR")
		return
	}
	offset = PackUint16(header.Type, buf, offset)
	offset = PackUint16(header.Class, buf, offset)
	offset = PackUint32(header.Ttl, buf, offset)
	start := offset + 2
	offset, err = rr.PackRData(buf, start)
	if err != nil {
		return
	}
	header.RDLength = uint16(offset - start)
	PackUint16(header.RDLength, buf, start-2)
	return
}
예제 #15
0
func (message *Message) Pack(data []byte, needCompress bool) (length int, err error) {
	var compression map[string]int
	if needCompress {
		compression = make(map[string]int) // Compression pointer mappings
	} else {
		compression = nil
	}

	length = 0
	dataLen := len(data)
	if dataLen < HEADER_LENGTH {
		err = errors.New("too short")
		return
	}
	length = PackUint16(message.Hdr.Id, data, length)
	if message.Hdr.QueryResponse == QR_RESPONSE {
		data[length] |= _QUREY_RESPONSE
	}
	data[length] |= message.Hdr.Opcode << 4 >> 1
	if message.Hdr.AuthAnswer {
		data[length] |= _AUTH_ANSWER
	}
	if message.Hdr.Truncated {
		data[length] |= _TRUNCATED
	}
	if message.Hdr.RecursionDesired {
		data[length] |= _RECURSION_DESIRED
	}
	length++
	if message.Hdr.RecursionAvailable {
		data[length] |= _RECURSION_AVAILABLE
	}
	data[length] |= message.Hdr.Zero << 5 >> 1
	data[length] |= message.Hdr.Rcode & _RCODE
	length++

	message.Hdr.QDCount = uint16(len(message.Question))
	message.Hdr.ANCount = uint16(len(message.Answer))
	message.Hdr.NSCount = uint16(len(message.Authority))
	message.Hdr.ARCount = uint16(len(message.Additional))
	length = PackUint16(message.Hdr.QDCount, data, length)
	length = PackUint16(message.Hdr.ANCount, data, length)
	length = PackUint16(message.Hdr.NSCount, data, length)
	length = PackUint16(message.Hdr.ARCount, data, length)
	for _, question := range message.Question {
		length, err = packQuestion(data, length, &question, compression)
		if err != nil {
			return
		}
	}
	length, err = packRRs(message.Answer, data, length, compression)
	if err != nil {
		return
	}
	//length, err = packRRs(message.Authority, data, length)
	//if err != nil {
	//return
	//}
	//length, err = packRRs(message.Additional, data, length)
	//if err != nil {
	//return
	//}
	return
}
예제 #16
0
파일: rr_mx.go 프로젝트: public0821/gotemp
func (m *RRMx) UnpackRData(buf []byte, index int) (offset int, err error) {
	err = errors.New("unsupport unpack mx record ")
	return
}