Skip to content
Snippets Groups Projects
format.go 2.4 KiB
Newer Older
  • Learn to ignore specific revisions
  • package dns
    
    import (
    	"net"
    	"reflect"
    	"strconv"
    )
    
    // NumField returns the number of rdata fields r has.
    func NumField(r RR) int {
    	return reflect.ValueOf(r).Elem().NumField() - 1 // Remove RR_Header
    }
    
    // Field returns the rdata field i as a string. Fields are indexed starting from 1.
    // RR types that holds slice data, for instance the NSEC type bitmap will return a single
    // string where the types are concatenated using a space.
    // Accessing non existing fields will cause a panic.
    func Field(r RR, i int) string {
    	if i == 0 {
    		return ""
    	}
    	d := reflect.ValueOf(r).Elem().Field(i)
    
    	switch d.Kind() {
    
    	case reflect.String:
    		return d.String()
    	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
    		return strconv.FormatInt(d.Int(), 10)
    	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
    		return strconv.FormatUint(d.Uint(), 10)
    	case reflect.Slice:
    		switch reflect.ValueOf(r).Elem().Type().Field(i).Tag {
    		case `dns:"a"`:
    			// TODO(miek): Hmm store this as 16 bytes
    
    			if d.Len() < net.IPv4len {
    				return ""
    			}
    
    			if d.Len() < net.IPv6len {
    				return net.IPv4(byte(d.Index(0).Uint()),
    					byte(d.Index(1).Uint()),
    					byte(d.Index(2).Uint()),
    					byte(d.Index(3).Uint())).String()
    			}
    			return net.IPv4(byte(d.Index(12).Uint()),
    				byte(d.Index(13).Uint()),
    				byte(d.Index(14).Uint()),
    				byte(d.Index(15).Uint())).String()
    		case `dns:"aaaa"`:
    
    			if d.Len() < net.IPv6len {
    				return ""
    			}
    
    			return net.IP{
    				byte(d.Index(0).Uint()),
    				byte(d.Index(1).Uint()),
    				byte(d.Index(2).Uint()),
    				byte(d.Index(3).Uint()),
    				byte(d.Index(4).Uint()),
    				byte(d.Index(5).Uint()),
    				byte(d.Index(6).Uint()),
    				byte(d.Index(7).Uint()),
    				byte(d.Index(8).Uint()),
    				byte(d.Index(9).Uint()),
    				byte(d.Index(10).Uint()),
    				byte(d.Index(11).Uint()),
    				byte(d.Index(12).Uint()),
    				byte(d.Index(13).Uint()),
    				byte(d.Index(14).Uint()),
    				byte(d.Index(15).Uint()),
    			}.String()
    		case `dns:"nsec"`:
    			if d.Len() == 0 {
    				return ""
    			}
    			s := Type(d.Index(0).Uint()).String()
    			for i := 1; i < d.Len(); i++ {
    				s += " " + Type(d.Index(i).Uint()).String()
    			}
    			return s
    		default:
    			// if it does not have a tag its a string slice
    			fallthrough
    		case `dns:"txt"`:
    			if d.Len() == 0 {
    				return ""
    			}
    			s := d.Index(0).String()
    			for i := 1; i < d.Len(); i++ {
    				s += " " + d.Index(i).String()
    			}
    			return s
    		}
    	}
    	return ""
    }