/* SPDX-License-Identifier: MIT * * Copyright (C) 2019-2026 WireGuard LLC. All Rights Reserved. * * This is a direct translation of the original C, and for that reason, it's pretty unusual Go code: * https://git.zx2c4.com/wireguard-tools/tree/contrib/highlighter/highlighter.c */ package syntax import "unsafe" type highlight int const ( highlightSection highlight = iota highlightField highlightPrivateKey highlightPublicKey highlightPresharedKey highlightIP highlightCidr highlightHost highlightPort highlightMTU highlightKeepalive highlightComment highlightDelimiter highlightTable highlightCmd highlightSecret highlightKeyword highlightError ) func validateHighlight(isValid bool, t highlight) highlight { if isValid { return t } return highlightError } type highlightSpan struct { t highlight s int len int } func isDecimal(c byte) bool { return c >= '0' && c <= '9' } func isHexadecimal(c byte) bool { return isDecimal(c) || (c|32) >= 'a' && (c|32) <= 'f' } func isAlphabet(c byte) bool { return (c|32) >= 'a' && (c|32) <= 'z' } type stringSpan struct { s *byte len int } func (s stringSpan) at(i int) *byte { return (*byte)(unsafe.Add(unsafe.Pointer(s.s), uintptr(i))) } func (s stringSpan) isSame(c string) bool { if s.len != len(c) { return false } cb := ([]byte)(c) for i := 0; i < s.len; i++ { if *s.at(i) != cb[i] { return false } } return true } func (s stringSpan) isCaselessSame(c string) bool { if s.len != len(c) { return false } cb := ([]byte)(c) for i := 0; i < s.len; i++ { a := *s.at(i) b := cb[i] if a-'a' < 26 { a &= 95 } if b-'a' < 26 { b &= 95 } if a != b { return false } } return true } func (s stringSpan) isValidKey() bool { if s.len != 44 || *s.at(43) != '=' { return false } for i := range 42 { if !isDecimal(*s.at(i)) && !isAlphabet(*s.at(i)) && *s.at(i) != '/' && *s.at(i) != '+' { return false } } switch *s.at(42) { case 'A', 'E', 'I', 'M', 'Q', 'U', 'Y', 'c', 'g', 'k', 'o', 's', 'w', '4', '8', '0': return true } return false } func (s stringSpan) isValidHostname() bool { numDigit := 0 numEntity := s.len if s.len > 63 || s.len == 0 { return false } if *s.s == '-' || *s.at(s.len - 1) == '-' { return false } if *s.s == '.' || *s.at(s.len - 1) == '.' { return false } for i := 0; i < s.len; i++ { if isDecimal(*s.at(i)) { numDigit++ continue } if *s.at(i) == '.' { numEntity-- continue } if !isAlphabet(*s.at(i)) && *s.at(i) != '-' { return false } if i != 0 && *s.at(i) == '.' && *s.at(i - 1) == '.' { return false } } return numDigit != numEntity } func (s stringSpan) isValidIPv4() bool { pos := 0 for i := 0; i < 4 && pos < s.len; i++ { val := 0 j := 0 for ; j < 3 && pos+j < s.len && isDecimal(*s.at(pos + j)); j++ { val = 10*val + int(*s.at(pos + j)-'0') } if j == 0 || j > 1 && *s.at(pos) == '0' || val > 255 { return false } if pos+j == s.len && i == 3 { return true } if *s.at(pos + j) != '.' { return false } pos += j + 1 } return false } func (s stringSpan) isValidIPv6() bool { if s.len < 2 { return false } pos := 0 if *s.at(0) == ':' { if *s.at(1) != ':' { return false } pos = 1 } if *s.at(s.len - 1) == ':' && *s.at(s.len - 2) != ':' { return false } seenColon := false for i := 0; pos < s.len; i++ { if *s.at(pos) == ':' && !seenColon { seenColon = true pos++ if pos == s.len { break } if i == 7 { return false } continue } j := 0 for ; ; j++ { if j < 4 && pos+j < s.len && isHexadecimal(*s.at(pos + j)) { continue } break } if j == 0 { return false } if pos+j == s.len && (seenColon || i == 7) { break } if i == 7 { return false } if *s.at(pos + j) != ':' { if *s.at(pos + j) != '.' || i < 6 && !seenColon { return false } return stringSpan{s.at(pos), s.len - pos}.isValidIPv4() } pos += j + 1 } return true } func (s stringSpan) isValidUint(supportHex bool, min, max uint64) bool { // Bound this around 32 bits, so that we don't have to write overflow logic. if s.len > 10 || s.len == 0 { return false } val := uint64(0) if supportHex && s.len > 2 && *s.s == '0' && *s.at(1) == 'x' { for i := 2; i < s.len; i++ { if *s.at(i)-'0' < 10 { val = 16*val + uint64(*s.at(i)-'0') } else if (*s.at(i))|32-'a' < 6 { val = 16*val + uint64((*s.at(i)|32)-'a'+10) } else { return false } } } else { for i := 0; i < s.len; i++ { if !isDecimal(*s.at(i)) { return false } val = 10*val + uint64(*s.at(i)-'0') } } return val <= max && val >= min } func (s stringSpan) isValidPort() bool { return s.isValidUint(false, 0, 65535) } func (s stringSpan) isValidMTU() bool { return s.isValidUint(false, 576, 65535) } func (s stringSpan) isValidMasking() bool { return s.isCaselessSame("none") || s.isCaselessSame("auto") || s.isCaselessSame("stun") || s.isCaselessSame("media") || s.isCaselessSame("tls") } func (s stringSpan) isValidObfuscationMode() bool { return s.isCaselessSame("wireguard") || s.isCaselessSame("socks5") } func (s stringSpan) isValidObfuscationRole() bool { return s.isCaselessSame("client") } func (s stringSpan) isValidSecret() bool { if s.len == 0 { return false } for i := range s.len { if *s.at(i) <= ' ' { return false } } return true } func (s stringSpan) isValidSourceInterface() bool { return s.isValidIPv4() || s.isValidIPv6() || s.isValidHostname() } func (s stringSpan) isValidTable() bool { return s.isSame("off") || s.isSame("auto") || s.isSame("main") || s.isValidUint(false, 0, (1<<32)-1) } func (s stringSpan) isValidPersistentKeepAlive() bool { if s.isSame("off") { return true } return s.isValidUint(false, 0, 65535) } // It's probably not worthwhile to try to validate a bash expression. So instead we just demand non-zero length. func (s stringSpan) isValidPrePostUpDown() bool { return s.len != 0 } func (s stringSpan) isValidScope() bool { if s.len > 64 || s.len == 0 { return false } for i := 0; i < s.len; i++ { if !isAlphabet(*s.at(i)) && !isDecimal(*s.at(i)) && *s.at(i) != '_' && *s.at(i) != '=' && *s.at(i) != '+' && *s.at(i) != '.' && *s.at(i) != '-' { return false } } return true } func (s stringSpan) isValidEndpoint() bool { if s.len == 0 { return false } if *s.s == '[' { seenScope := false hostspan := stringSpan{s.at(1), 0} for i := 1; i < s.len; i++ { if *s.at(i) == '%' { if seenScope { return false } seenScope = true if !hostspan.isValidIPv6() { return false } hostspan = stringSpan{s.at(i + 1), 0} } else if *s.at(i) == ']' { if seenScope { if !hostspan.isValidScope() { return false } } else if !hostspan.isValidIPv6() { return false } if i == s.len-1 || *s.at((i + 1)) != ':' { return false } return stringSpan{s.at(i + 2), s.len - i - 2}.isValidPort() } else { hostspan.len++ } } return false } for i := 0; i < s.len; i++ { if *s.at(i) == ':' { host := stringSpan{s.s, i} port := stringSpan{s.at(i + 1), s.len - i - 1} return port.isValidPort() && (host.isValidIPv4() || host.isValidHostname()) } } return false } func (s stringSpan) isValidNetwork() bool { for i := 0; i < s.len; i++ { if *s.at(i) == '/' { ip := stringSpan{s.s, i} cidr := stringSpan{s.at(i + 1), s.len - i - 1} cidrval := uint16(0) if cidr.len > 3 || cidr.len == 0 { return false } for j := 0; j < cidr.len; j++ { if !isDecimal(*cidr.at(j)) { return false } cidrval = 10*cidrval + uint16(*cidr.at(j)-'0') } if ip.isValidIPv4() { return cidrval <= 32 } else if ip.isValidIPv6() { return cidrval <= 128 } return false } } return s.isValidIPv4() || s.isValidIPv6() } type field int32 const ( fieldInterfaceSection field = iota fieldPrivateKey fieldListenPort fieldAddress fieldDNS fieldMTU fieldTable fieldPreUp fieldPostUp fieldPreDown fieldPostDown fieldPeerSection fieldPublicKey fieldPresharedKey fieldAllowedIPs fieldEndpoint fieldPersistentKeepalive fieldInstanceSection fieldObfuscationMode fieldObfuscationRole fieldSourceInterface fieldSourceListenPort fieldTarget fieldObfuscationKey fieldMasking fieldObfuscateBytes fieldMaxDummy fieldMediaPayloadType fieldMediaSSRC fieldMediaClock fieldVerbose fieldSocks5Section fieldLogin fieldPassword fieldInvalid ) func sectionForField(t field) field { if t > fieldInterfaceSection && t < fieldPeerSection { return fieldInterfaceSection } if t > fieldPeerSection && t < fieldInstanceSection { return fieldPeerSection } if t > fieldInstanceSection && t < fieldSocks5Section { return fieldInstanceSection } if t > fieldSocks5Section && t < fieldInvalid { return fieldSocks5Section } return fieldInvalid } func (s stringSpan) field() field { switch { case s.isCaselessSame("PrivateKey"): return fieldPrivateKey case s.isCaselessSame("ListenPort"): return fieldListenPort case s.isCaselessSame("Address"): return fieldAddress case s.isCaselessSame("DNS"): return fieldDNS case s.isCaselessSame("MTU"): return fieldMTU case s.isCaselessSame("Table"): return fieldTable case s.isCaselessSame("PublicKey"): return fieldPublicKey case s.isCaselessSame("PresharedKey"): return fieldPresharedKey case s.isCaselessSame("AllowedIPs"): return fieldAllowedIPs case s.isCaselessSame("Endpoint"): return fieldEndpoint case s.isCaselessSame("PersistentKeepalive"): return fieldPersistentKeepalive case s.isCaselessSame("PreUp"): return fieldPreUp case s.isCaselessSame("PostUp"): return fieldPostUp case s.isCaselessSame("PreDown"): return fieldPreDown case s.isCaselessSame("PostDown"): return fieldPostDown case s.isCaselessSame("mode"): return fieldObfuscationMode case s.isCaselessSame("role"): return fieldObfuscationRole case s.isCaselessSame("source-if"): return fieldSourceInterface case s.isCaselessSame("source-lport"): return fieldSourceListenPort case s.isCaselessSame("target"): return fieldTarget case s.isCaselessSame("key"): return fieldObfuscationKey case s.isCaselessSame("masking"): return fieldMasking case s.isCaselessSame("obfuscate-bytes"): return fieldObfuscateBytes case s.isCaselessSame("max-dummy"): return fieldMaxDummy case s.isCaselessSame("media-pt"): return fieldMediaPayloadType case s.isCaselessSame("media-ssrc"): return fieldMediaSSRC case s.isCaselessSame("media-clock"): return fieldMediaClock case s.isCaselessSame("verbose"): return fieldVerbose case s.isCaselessSame("login"): return fieldLogin case s.isCaselessSame("password"): return fieldPassword } return fieldInvalid } func (s stringSpan) sectionType() field { switch { case s.isCaselessSame("[Peer]"): return fieldPeerSection case s.isCaselessSame("[Interface]"): return fieldInterfaceSection case s.isCaselessSame("[Instance]"): return fieldInstanceSection case s.isCaselessSame("[Socks5]"): return fieldSocks5Section } return fieldInvalid } type highlightSpanArray []highlightSpan func (hsa *highlightSpanArray) append(o *byte, s stringSpan, t highlight) { if s.len == 0 { return } *hsa = append(*hsa, highlightSpan{t, int((uintptr(unsafe.Pointer(s.s))) - (uintptr(unsafe.Pointer(o)))), s.len}) } func (hsa *highlightSpanArray) highlightMultivalueValue(parent, s stringSpan, section field) { switch section { case fieldDNS: if s.isValidIPv4() || s.isValidIPv6() { hsa.append(parent.s, s, highlightIP) } else if s.isValidHostname() { hsa.append(parent.s, s, highlightHost) } else { hsa.append(parent.s, s, highlightError) } case fieldAddress, fieldAllowedIPs: if !s.isValidNetwork() { hsa.append(parent.s, s, highlightError) break } slash := 0 for ; slash < s.len; slash++ { if *s.at(slash) == '/' { break } } if slash == s.len { hsa.append(parent.s, s, highlightIP) } else { hsa.append(parent.s, stringSpan{s.s, slash}, highlightIP) hsa.append(parent.s, stringSpan{s.at(slash), 1}, highlightDelimiter) hsa.append(parent.s, stringSpan{s.at(slash + 1), s.len - slash - 1}, highlightCidr) } default: hsa.append(parent.s, s, highlightError) } } func (hsa *highlightSpanArray) highlightMultivalue(parent, s stringSpan, section field) { currentSpan := stringSpan{s.s, 0} lenAtLastSpace := 0 for i := 0; i < s.len; i++ { if *s.at(i) == ',' { currentSpan.len = lenAtLastSpace hsa.highlightMultivalueValue(parent, currentSpan, section) hsa.append(parent.s, stringSpan{s.at(i), 1}, highlightDelimiter) lenAtLastSpace = 0 currentSpan = stringSpan{s.at(i + 1), 0} } else if *s.at(i) == ' ' || *s.at(i) == '\t' { if s.at(i) == currentSpan.s && currentSpan.len == 0 { currentSpan.s = currentSpan.at(1) } else { currentSpan.len++ } } else { currentSpan.len++ lenAtLastSpace = currentSpan.len } } currentSpan.len = lenAtLastSpace if currentSpan.len != 0 { hsa.highlightMultivalueValue(parent, currentSpan, section) } else if (*hsa)[len(*hsa)-1].t == highlightDelimiter { (*hsa)[len(*hsa)-1].t = highlightError } } func (hsa *highlightSpanArray) highlightValue(parent, s stringSpan, section field) { switch section { case fieldPrivateKey: hsa.append(parent.s, s, validateHighlight(s.isValidKey(), highlightPrivateKey)) case fieldPublicKey: hsa.append(parent.s, s, validateHighlight(s.isValidKey(), highlightPublicKey)) case fieldPresharedKey: hsa.append(parent.s, s, validateHighlight(s.isValidKey(), highlightPresharedKey)) case fieldMTU: hsa.append(parent.s, s, validateHighlight(s.isValidMTU(), highlightMTU)) case fieldTable: hsa.append(parent.s, s, validateHighlight(s.isValidTable(), highlightTable)) case fieldPreUp, fieldPostUp, fieldPreDown, fieldPostDown: hsa.append(parent.s, s, validateHighlight(s.isValidPrePostUpDown(), highlightCmd)) case fieldListenPort: hsa.append(parent.s, s, validateHighlight(s.isValidPort(), highlightPort)) case fieldPersistentKeepalive: hsa.append(parent.s, s, validateHighlight(s.isValidPersistentKeepAlive(), highlightKeepalive)) case fieldEndpoint, fieldTarget: if !s.isValidEndpoint() { hsa.append(parent.s, s, highlightError) break } colon := s.len for colon > 0 { colon-- if *s.at(colon) == ':' { break } } hsa.append(parent.s, stringSpan{s.s, colon}, highlightHost) hsa.append(parent.s, stringSpan{s.at(colon), 1}, highlightDelimiter) hsa.append(parent.s, stringSpan{s.at(colon + 1), s.len - colon - 1}, highlightPort) case fieldObfuscationMode: hsa.append(parent.s, s, validateHighlight(s.isValidObfuscationMode(), highlightKeyword)) case fieldObfuscationRole: hsa.append(parent.s, s, validateHighlight(s.isValidObfuscationRole(), highlightKeyword)) case fieldMasking: hsa.append(parent.s, s, validateHighlight(s.isValidMasking(), highlightKeyword)) case fieldSourceInterface: hsa.append(parent.s, s, validateHighlight(s.isValidSourceInterface(), highlightHost)) case fieldSourceListenPort: hsa.append(parent.s, s, validateHighlight(s.isValidPort(), highlightPort)) case fieldObfuscationKey, fieldLogin, fieldPassword: hsa.append(parent.s, s, validateHighlight(s.isValidSecret(), highlightSecret)) case fieldObfuscateBytes, fieldMaxDummy: hsa.append(parent.s, s, validateHighlight(s.isValidUint(false, 0, 65535), highlightMTU)) case fieldMediaPayloadType: hsa.append(parent.s, s, validateHighlight(s.isValidUint(false, 0, 127), highlightMTU)) case fieldMediaSSRC: hsa.append(parent.s, s, validateHighlight(s.isValidUint(true, 0, (1<<32)-1), highlightMTU)) case fieldMediaClock: hsa.append(parent.s, s, validateHighlight(s.isValidUint(false, 0, 1000), highlightMTU)) case fieldVerbose: hsa.append(parent.s, s, validateHighlight(s.isValidUint(false, 0, 4), highlightMTU)) case fieldAddress, fieldDNS, fieldAllowedIPs: hsa.highlightMultivalue(parent, s, section) default: hsa.append(parent.s, s, highlightError) } } func highlightConfig(config string) []highlightSpan { var ret highlightSpanArray b := append([]byte(config), 0) s := stringSpan{&b[0], len(b) - 1} currentSpan := stringSpan{s.s, 0} currentSection := fieldInvalid currentField := fieldInvalid const ( onNone = iota onKey onValue onComment onSection ) state := onNone lenAtLastSpace := 0 equalsLocation := 0 for i := 0; i <= s.len; i++ { if i == s.len || *s.at(i) == '\n' || state != onComment && *s.at(i) == '#' { if state == onKey { currentSpan.len = lenAtLastSpace ret.append(s.s, currentSpan, highlightError) } else if state == onValue { if currentSpan.len != 0 { ret.append(s.s, stringSpan{s.at(equalsLocation), 1}, highlightDelimiter) currentSpan.len = lenAtLastSpace ret.highlightValue(s, currentSpan, currentField) } else { ret.append(s.s, stringSpan{s.at(equalsLocation), 1}, highlightError) } } else if state == onSection { currentSpan.len = lenAtLastSpace currentSection = currentSpan.sectionType() ret.append(s.s, currentSpan, validateHighlight(currentSection != fieldInvalid, highlightSection)) } else if state == onComment { ret.append(s.s, currentSpan, highlightComment) } if i == s.len { break } lenAtLastSpace = 0 currentField = fieldInvalid if *s.at(i) == '#' { currentSpan = stringSpan{s.at(i), 1} state = onComment } else { currentSpan = stringSpan{s.at(i + 1), 0} state = onNone } } else if state == onComment { currentSpan.len++ } else if *s.at(i) == ' ' || *s.at(i) == '\t' { if s.at(i) == currentSpan.s && currentSpan.len == 0 { currentSpan.s = currentSpan.at(1) } else { currentSpan.len++ } } else if *s.at(i) == '=' && state == onKey { currentSpan.len = lenAtLastSpace currentField = currentSpan.field() section := sectionForField(currentField) if section == fieldInvalid || currentField == fieldInvalid || section != currentSection { ret.append(s.s, currentSpan, highlightError) } else { ret.append(s.s, currentSpan, highlightField) } equalsLocation = i currentSpan = stringSpan{s.at(i + 1), 0} state = onValue } else { if state == onNone { if *s.at(i) == '[' { state = onSection } else { state = onKey } } currentSpan.len++ lenAtLastSpace = currentSpan.len } } return ([]highlightSpan)(ret) }