github.com/DataDog/datadog-agent/pkg/security/secl@v0.55.0-devel.0.20240517055856-10c4965fea94/model/dns_helpers_linux.go (about)

     1  // Unless explicitly stated otherwise all files in this repository are licensed
     2  // under the Apache License Version 2.0.
     3  // This product includes software developed at Datadog (https://www.datadoghq.com/).
     4  // Copyright 2016-present Datadog, Inc.
     5  
     6  //go:build linux
     7  
     8  // Package model holds model related files
     9  package model
    10  
    11  import (
    12  	"errors"
    13  	"strings"
    14  )
    15  
    16  var (
    17  	// ErrDNSNamePointerNotSupported reported because pointer compression is not supported
    18  	ErrDNSNamePointerNotSupported = errors.New("dns name pointer compression is not supported")
    19  	// ErrDNSNameOutOfBounds reported because name out of bound
    20  	ErrDNSNameOutOfBounds = errors.New("dns name out of bound")
    21  	// ErrDNSNameNonPrintableASCII reported because name non-printable ascii
    22  	ErrDNSNameNonPrintableASCII = errors.New("dns name non-printable ascii")
    23  	// ErrDNSNameMalformatted reported because name mal formatted (too short, missing dots, etc)
    24  	ErrDNSNameMalformatted = errors.New("dns name mal-formatted")
    25  )
    26  
    27  // DNSPreallocSize defines DNS pre-alloc size
    28  const DNSPreallocSize = 256
    29  
    30  func decodeDNSName(raw []byte) (string, error) {
    31  	var (
    32  		i       = 0
    33  		rawLen  = len(raw)
    34  		atStart = true
    35  		rep     strings.Builder
    36  		err     error
    37  	)
    38  
    39  	rep.Grow(DNSPreallocSize)
    40  
    41  LOOP:
    42  	for i < rawLen {
    43  		// Parse label length
    44  		labelLen := int(raw[i])
    45  		i++
    46  
    47  		if labelLen == 0 {
    48  			// end of name
    49  			break
    50  		}
    51  
    52  		if labelLen&0xC0 != 0 {
    53  			// pointer compression, we do not support this yet
    54  			err = ErrDNSNamePointerNotSupported
    55  			break
    56  		}
    57  
    58  		if rawLen < i+labelLen {
    59  			// out of bounds
    60  			err = ErrDNSNameOutOfBounds
    61  			break
    62  		}
    63  
    64  		labelRaw := raw[i : i+labelLen]
    65  
    66  		if !atStart {
    67  			rep.WriteRune('.')
    68  		}
    69  		for _, c := range labelRaw {
    70  			if c < ' ' || '~' < c {
    71  				// non-printable ascii char
    72  				err = ErrDNSNameNonPrintableASCII
    73  				break LOOP
    74  			}
    75  		}
    76  		rep.Write(labelRaw)
    77  
    78  		atStart = false
    79  		i += labelLen
    80  	}
    81  
    82  	return rep.String(), err
    83  }
    84  
    85  func validateDNSName(dns string) error {
    86  	if dns == "" {
    87  		return nil
    88  	}
    89  
    90  	// Maximum length of the DNS name field in the DNS protocol is 255 bytes:
    91  	//
    92  	//                  <------------- 255 --------------->
    93  	//                  | X | ... | Y | ... | Z | ... | 0 |
    94  	//
    95  	// If you remove the trailing 0 and the first X (which isn't turned into a `.` in the string representation), you
    96  	// get a maximum printable characters length of 253.
    97  	if len(dns) > 253 {
    98  		return ErrDNSNameMalformatted
    99  	}
   100  
   101  	// Check that the DNS doesn't start or end with a dot.
   102  	if dns[0] == '.' || dns[len(dns)-1] == '.' {
   103  		return ErrDNSNameMalformatted
   104  	}
   105  
   106  	// Check that each label isn't empty and at most 63 characters.
   107  	previousIndex := -1
   108  	for previousIndex < len(dns) {
   109  		delta := strings.IndexByte(dns[previousIndex+1:], '.')
   110  		if delta < 0 {
   111  			break
   112  		}
   113  
   114  		if delta < 1 || delta > 63 {
   115  			return ErrDNSNameMalformatted
   116  		}
   117  
   118  		previousIndex += delta + 1
   119  	}
   120  
   121  	return nil
   122  }