Documentation
¶
Index ¶
- Constants
- Variables
- func ClassToString(c uint16) string
- func DecodeDomainName(data []byte, offset int) (string, int, error)
- func EncodeDomainName(name string) ([]byte, error)
- func EncodeQuestion(q Question) ([]byte, error)
- func EncodeResourceRecord(rr ResourceRecord) ([]byte, error)
- func FlagToString(f uint16) string
- func HandlerDescribePacket(server *Server, remoteAddr net.Addr, writer ResponseWriter, message *Message) bool
- func HandlerDescribePacketJson(server *Server, remoteAddr net.Addr, writer ResponseWriter, message *Message) bool
- func IPToRData(ip string) []byte
- func IPv4ToRData(ip string) []byte
- func IPv6ToRData(ip string) []byte
- func TypeToString(t uint16) string
- func ValidateDomainName(name string) error
- type Client
- type Handler
- type HandlerFunc
- type Header
- type Message
- func (m *Message) AddAnswer(rr ResourceRecord) error
- func (m *Message) AddAnswerClassINTypeA(name, ip string) error
- func (m *Message) AddAnswerClassINTypeAAAA(name, ip string) error
- func (m *Message) AddQuestion(name string, qtype, qclass uint16) error
- func (m *Message) Encode() ([]byte, error)
- func (m *Message) IsQuery() bool
- func (m *Message) IsResponse() bool
- func (m *Message) SetQuery()
- func (m *Message) SetResponse()
- func (m *Message) Validate() error
- type Question
- type ResourceRecord
- type ResponseWriter
- type Server
Constants ¶
const ( // LLMNR uses port 5355 as specified in RFC 4795 LLMNRPort = 5355 // Multicast addresses for LLMNR IPv4MulticastAddr = "224.0.0.252" IPv6MulticastAddr = "FF02::1:3" MaxLabelLength = 63 // Maximum length of a single label MaxDomainLength = 255 // Maximum length of entire domain name HeaderSize = 12 // Size of LLMNR header in bytes MaxPacketSize = 512 )
const ( FlagQR = 1 << 15 // Query/Response flag FlagOP = 1 << 14 // Operation code FlagC = 1 << 13 // Conflict flag FlagTC = 1 << 12 // Truncation flag FlagT = 1 << 11 // Tentative flag )
LLMNR Header Flags
const ( TypeA uint16 = 1 // IPv4 address TypeNS uint16 = 2 // Authoritative name server TypeCNAME uint16 = 5 // Canonical name for an alias TypeSOA uint16 = 6 // Start of authority TypePTR uint16 = 12 // Domain name pointer TypeMX uint16 = 15 // Mail exchange TypeTXT uint16 = 16 // Text strings TypeAAAA uint16 = 28 // IPv6 address TypeSRV uint16 = 33 // Service locator TypeOPT uint16 = 41 // OPT pseudo-RR, RFC 2671 TypeAXFR uint16 = 252 // Transfer of entire zone TypeALL uint16 = 255 // All records )
Resource Record Types
const ( ClassIN uint16 = 1 // Internet ClassCS uint16 = 2 // CSNET (Obsolete) ClassCH uint16 = 3 // CHAOS ClassHS uint16 = 4 // Hesiod ClassNONE uint16 = 254 // Used in dynamic update messages ClassANY uint16 = 255 // Any class ClassQU uint16 = 1 // QU flag for LLMNR (same as IN) ClassUNICAST uint16 = 0x8001 // LLMNR Unicast response )
Resource Record Classes
Variables ¶
var ( ErrNameTooLong = errors.New("domain name too long") ErrLabelTooLong = errors.New("label too long") )
Common errors
var ( ErrInvalidQuestion = errors.New("invalid question format") ErrInvalidMessage = errors.New("invalid message format") )
Common errors
Functions ¶
func ClassToString ¶
func DecodeDomainName ¶
DecodeDomainName decodes a byte slice into a domain name string in the wire format as specified by the LLMNR protocol. The function processes the byte slice to extract the sequence of labels, handling pointers if present, and reconstructs the original domain name.
Parameters: - data: A byte slice containing the encoded domain name in wire format. - offset: The starting position in the byte slice from which to begin decoding.
Returns:
- A string containing the decoded domain name.
- An integer representing the new offset position after decoding.
- An error if the decoding fails at any point, such as if the data is too short, if there is an invalid pointer, or if a label is too long.
Usage example:
data := []byte{7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 5, 'l', 'o', 'c', 'a', 'l', 0}
offset := 0
domainName, newOffset, err := DecodeDomainName(data, offset)
if err != nil {
log.Fatalf("Failed to decode domain name: %v", err)
}
fmt.Printf("Decoded domain name: %s, New offset: %d\n", domainName, newOffset)
The resulting domain name for the given byte slice would be "example.local" and the new offset would be 14.
func EncodeDomainName ¶
EncodeDomainName encodes a domain name into a byte slice in the wire format as specified by the LLMNR protocol. The function converts the domain name into a sequence of labels, each prefixed by its length, and ends with a zero byte.
Parameters: - name: The domain name to be encoded.
Returns:
- A byte slice containing the encoded domain name.
- An error if the encoding fails, such as if a label is too long.
Usage example:
encodedName, err := EncodeDomainName("example.local")
if err != nil {
log.Fatalf("Failed to encode domain name: %v", err)
}
The resulting byte slice for "example.local" would be:
[]byte{7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 5, 'l', 'o', 'c', 'a', 'l', 0}
func EncodeQuestion ¶
Usage:
buf, err := EncodeQuestion(buf, question)
if err != nil {
// handle error
}
The function returns the updated byte slice with the encoded question appended to it, or an error if the domain name encoding fails.
func EncodeResourceRecord ¶
func EncodeResourceRecord(rr ResourceRecord) ([]byte, error)
EncodeResourceRecord converts a ResourceRecord into a byte slice using the LLMNR protocol's wire format. It encodes the domain name, type, class, TTL, RDLength, and RData fields sequentially.
Parameters: - rr: The ResourceRecord to be encoded.
Returns:
- A byte slice with the encoded resource record.
- An error if encoding fails, such as with an invalid domain name.
Example usage:
rr := ResourceRecord{
Name: "example.local",
Type: TypeA,
Class: ClassIN,
TTL: 300,
RDLength: 4,
RData: []byte{192, 168, 1, 1},
}
encodedBuf, err := EncodeResourceRecord(rr)
if err != nil {
log.Fatalf("Failed to encode resource record: %v", err)
}
func FlagToString ¶
func HandlerDescribePacket ¶
func HandlerDescribePacket(server *Server, remoteAddr net.Addr, writer ResponseWriter, message *Message) bool
HandlerDescribePacket logs detailed information about an LLMNR packet received by the server.
Parameters: - server: A pointer to the Server that received the packet. - remoteAddr: The address of the remote client that sent the packet. - writer: A ResponseWriter to send responses back to the client. - message: The LLMNR message received from the client.
The function logs the following details about the received LLMNR packet: - The remote address of the client that sent the packet. - The number of questions in the packet, and for each question:
- The class of the question.
- The type of the question.
- The name in the question.
- The number of answers in the packet, and for each answer:
- The class of the answer.
- The type of the answer.
- The name in the answer.
- The TTL (Time to Live) of the answer.
- The RDLENGTH (length of the RDATA field) of the answer.
- The RDATA (resource data) of the answer.
- The number of authority records in the packet, and for each authority record:
- The class of the authority record.
- The type of the authority record.
- The name in the authority record.
- The TTL (Time to Live) of the authority record.
- The RDLENGTH (length of the RDATA field) of the authority record.
- The RDATA (resource data) of the authority record.
The function uses a logger to output the information in a structured format, with indentation to represent the hierarchy of the packet's contents. The logger is locked during the function execution to ensure thread-safe logging.
func HandlerDescribePacketJson ¶
func HandlerDescribePacketJson(server *Server, remoteAddr net.Addr, writer ResponseWriter, message *Message) bool
HandlerDescribePacketJson logs the details of the LLMNR message in JSON format.
func IPToRData ¶
IPToRData converts an IP address string to its corresponding RData byte slice representation. It determines whether the IP address is IPv4 or IPv6 and calls the appropriate conversion function.
Parameters: - ip: A string representing the IP address to be converted.
Returns: - A byte slice containing the RData representation of the IP address. - nil if the IP address is neither a valid IPv4 nor IPv6 address.
Usage example:
rdata := IPToRData("192.168.1.1")
if rdata == nil {
log.Fatalf("Invalid IP address")
}
func IPv4ToRData ¶
IPv4ToRData converts an IPv4 address string to its corresponding RData byte slice representation.
Parameters: - ip: A string representing the IPv4 address to be converted.
Returns: - A byte slice containing the RData representation of the IPv4 address.
Usage example:
rdata := IPv4ToRData("192.168.1.1")
if rdata == nil {
log.Fatalf("Invalid IPv4 address")
}
func IPv6ToRData ¶
IPv6ToRData converts an IPv6 address string to its corresponding RData byte slice representation.
Parameters: - ip: A string representing the IPv6 address to be converted.
Returns: - A byte slice containing the RData representation of the IPv6 address.
Usage example:
rdata := IPv6ToRData("2001:0db8:85a3:0000:0000:8a2e:0370:7334")
if rdata == nil {
log.Fatalf("Invalid IPv6 address")
}
func TypeToString ¶
func ValidateDomainName ¶
ValidateDomainName validates a domain name according to the rules specified by the LLMNR protocol. The function checks if the domain name exceeds the maximum allowed length and if any label within the domain name exceeds the maximum allowed label length. A domain name is composed of labels separated by dots.
Parameters: - name: The domain name to be validated.
Returns:
- An error if the domain name is invalid, such as if it is too long or if any label is too long.
- nil if the domain name is valid.
Usage example:
err := ValidateDomainName("example.local")
if err != nil {
log.Fatalf("Invalid domain name: %v", err)
}
The function will return an error in the following cases: - If the domain name exceeds MaxDomainLength. - If any label within the domain name exceeds MaxLabelLength.
Types ¶
type Client ¶
type Client struct {
Conn *net.UDPConn
Timeout time.Duration
Queries sync.Map
CloseOnce sync.Once
Closed chan struct{}
}
Client represents an LLMNR client that can send queries and receive responses.
The Client struct provides methods to create a new client, send queries, and close the client connection. It manages a UDP connection and uses a sync.Map to keep track of ongoing queries.
Fields: - conn: A pointer to the UDP connection used for sending and receiving LLMNR messages. - timeout: The duration to wait for a response before timing out. - queries: A sync.Map that maps query IDs to channels for receiving responses. - closeOnce: Ensures the client is closed only once. - closed: A channel that is closed when the client is closed.
Usage example:
client, err := NewClient()
if err != nil {
log.Fatalf("Failed to create client: %v", err)
}
defer client.Close()
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
resp, err := client.Query(ctx, "example.local", TypeA)
if err != nil {
log.Fatalf("Query failed: %v", err)
}
fmt.Printf("Received response: %v\n", resp)
func NewClient ¶
NewClient creates a new LLMNR client with a UDP connection.
The function initializes a UDP connection for the client to use for sending and receiving LLMNR messages. It sets a default timeout duration for queries and starts a read loop to handle incoming responses.
Returns:
- A pointer to the newly created Client.
- An error if the UDP connection could not be created.
Usage example:
client, err := NewClient()
if err != nil {
log.Fatalf("Failed to create client: %v", err)
}
defer client.Close()
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
resp, err := client.Query(ctx, "example.local", TypeA)
if err != nil {
log.Fatalf("Query failed: %v", err)
}
fmt.Printf("Received response: %v\n", resp)
type Handler ¶
type Handler interface {
Run(server *Server, remoteAddr net.Addr, writer ResponseWriter, message *Message) bool
}
Handler defines the interface for processing LLMNR queries
type HandlerFunc ¶
HandlerFunc is an adapter to allow regular functions to serve as LLMNR handlers
func (HandlerFunc) Run ¶
func (f HandlerFunc) Run(server *Server, remoteAddr net.Addr, writer ResponseWriter, message *Message) bool
Run executes the handler function to process an LLMNR query.
Parameters: - server: The Server instance that received the query. - remoteAddr: The address of the client that sent the query. - writer: The ResponseWriter used to send responses back to the client. - message: The Message received from the client.
The function calls the handler function with the provided ResponseWriter and Message. It allows regular functions to be used as LLMNR handlers by adapting them to the Handler interface.
Example usage:
handlerFunc := func(w llmnr.ResponseWriter, r *llmnr.Message) {
// Process the LLMNR query and write a response
}
handler := llmnr.HandlerFunc(handlerFunc)
server.RegisterHandler(handler)
This function is typically called internally by the Server when a new LLMNR query is received.
type Header ¶
type Header struct {
ID uint16 `json:"id"`
Flags uint16 `json:"flags"`
QDCount uint16 `json:"qd_count"` // Question count
ANCount uint16 `json:"an_count"` // Answer count
NSCount uint16 `json:"ns_count"` // Authority count
ARCount uint16 `json:"ar_count"` // Additional count
}
Header represents the LLMNR message header.
The header contains essential information about the LLMNR message, including the message ID, flags, and counts of various sections such as questions, answers, authority records, and additional records.
Fields:
- ID: A 16-bit identifier assigned by the program that generates any kind of query. This identifier is copied to the corresponding reply and can be used by the requester to match up replies to outstanding queries.
- Flags: A 16-bit field containing various flags that control the message flow and interpretation. These flags include the Query/Response flag (QR), Operation code (OP), Conflict flag (C), Truncation flag (TC), and Tentative flag (T).
- QDCount: An unsigned 16-bit integer specifying the number of entries in the question section of the message.
- ANCount: An unsigned 16-bit integer specifying the number of resource records in the answer section of the message.
- NSCount: An unsigned 16-bit integer specifying the number of name server resource records in the authority records section of the message.
- ARCount: An unsigned 16-bit integer specifying the number of resource records in the additional records section of the message.
Usage example:
header := Header{
ID: 12345,
Flags: FlagQR,
QDCount: 1,
ANCount: 0,
NSCount: 0,
ARCount: 0,
}
type Message ¶
type Message struct {
Header
Questions []Question `json:"questions"`
Answers []ResourceRecord `json:"answers"`
Authority []ResourceRecord `json:"authority"`
Additional []ResourceRecord `json:"additional"`
}
Message represents an LLMNR message.
An LLMNR (Link-Local Multicast Name Resolution) message consists of a header and four sections: Questions, Answers, Authority, and Additional. The header contains metadata about the message, such as the transaction ID and various flags. The Questions section contains the questions being asked in the message, while the Answers, Authority, and Additional sections contain resource records that provide answers, authority information, and additional information, respectively.
Fields: - Header: The header of the LLMNR message, containing metadata such as the transaction ID and flags. - Questions: A slice of Question structs representing the questions in the message. - Answers: A slice of ResourceRecord structs representing the answers in the message. - Authority: A slice of ResourceRecord structs representing the authority records in the message. - Additional: A slice of ResourceRecord structs representing the additional records in the message.
func CreateResponseFromMessage ¶
CreateResponseFromMessage creates a new LLMNR message that is a response to the given message.
Parameters: - msg: The message to create a response for.
Returns: - A pointer to the newly created Message instance.
func DecodeMessage ¶
DecodeMessage decodes a byte slice into a Message struct. It expects the byte slice to be in the wire format as specified by the LLMNR protocol. The function first checks if the provided data is at least as long as the LLMNR header. It then proceeds to decode the header fields, followed by the question and answer sections.
Parameters: - data: A byte slice containing the LLMNR message in wire format.
Returns:
- A pointer to a Message struct containing the decoded data.
- An error if the decoding fails at any point, such as if the data is too short or if there is an error decoding the question or answer sections.
func NewMessage ¶
func NewMessage() *Message
NewMessage creates a new LLMNR message with a randomly generated transaction ID and initializes the Questions, Answers, Authority, and Additional sections as empty slices. The Header of the message is also initialized with the generated transaction ID.
Returns: - A pointer to the newly created Message instance.
func (*Message) AddAnswer ¶
func (m *Message) AddAnswer(rr ResourceRecord) error
AddAnswer adds a resource record to the Answers section of the LLMNR message and updates the answer count in the header. It validates the domain name of the resource record before adding it.
Parameters: - rr: The resource record to be added to the Answers section.
Returns: - An error if the domain name of the resource record is invalid. - nil if the resource record is successfully added.
func (*Message) AddAnswerClassINTypeA ¶
AddAnswerClassINTypeA adds a resource record with Class IN and Type A to the Answers section of the LLMNR message and updates the answer count in the header. It validates the domain name of the resource record before adding it.
Parameters: - name: The domain name for the resource record. - rdata: The resource data for the Type A record (e.g., an IPv4 address).
Returns: - An error if the domain name of the resource record is invalid. - nil if the resource record is successfully added.
func (*Message) AddAnswerClassINTypeAAAA ¶
AddAnswerClassINTypeAAAA adds a resource record with Class IN and Type AAAA to the Answers section of the LLMNR message and updates the answer count in the header. It validates the domain name of the resource record before adding it.
Parameters: - name: The domain name for the resource record. - rdata: The resource data for the Type AAAA record (e.g., an IPv6 address).
Returns: - An error if the domain name of the resource record is invalid. - nil if the resource record is successfully added.
func (*Message) AddQuestion ¶
AddQuestion adds a question to the Questions section of the LLMNR message and updates the question count in the header. It validates the domain name of the question before adding it.
Parameters: - name: The domain name for the question. - qtype: The type of the question (e.g., TypeA, TypeAAAA). - qclass: The class of the question (e.g., ClassIN).
Returns: - An error if the domain name is invalid. - nil if the question is successfully added.
func (*Message) Encode ¶
Encode serializes the Message struct into a byte slice according to the LLMNR wire format. It encodes the header, questions, and answers sections of the message.
Returns: - A byte slice containing the encoded message. - An error if encoding fails at any point, such as if there is an error encoding the questions or answers.
func (*Message) IsQuery ¶
IsQuery returns true if the message is a query.
This function checks the QR (Query/Response) flag in the message's Flags field. If the QR flag is not set, the message is considered a query and the function returns true. If the QR flag is set, the message is considered a response and the function returns false.
Returns:
- A boolean value indicating whether the message is a query (true) or not (false).
func (*Message) IsResponse ¶
IsResponse returns true if the message is a response.
This function checks the QR (Query/Response) flag in the message's Flags field. If the QR flag is set, the message is considered a response and the function returns true. If the QR flag is not set, the message is considered a query and the function returns false.
Returns:
- A boolean value indicating whether the message is a response (true) or not (false).
func (*Message) SetQuery ¶
func (m *Message) SetQuery()
SetQuery marks the message as a query.
This function clears the QR (Query/Response) flag in the message's Flags field. By clearing the QR flag, the message is considered a query.
Usage:
msg.SetQuery()
After calling this function, the message will be marked as a query.
Returns:
- Nothing. This function modifies the message in place.
func (*Message) SetResponse ¶
func (m *Message) SetResponse()
SetResponse marks the message as a response.
This function sets the QR (Query/Response) flag in the message's Flags field. By setting the QR flag, the message is considered a response.
Usage:
msg.SetResponse()
After calling this function, the message will be marked as a response.
Returns:
- Nothing. This function modifies the message in place.
func (*Message) Validate ¶
Validate checks the integrity of the LLMNR message by ensuring that the counts in the header match the actual number of questions, answers, authority, and additional records. It also validates the domain names in the questions and answers sections.
Returns: - An error if any of the counts do not match or if any domain name is invalid. - nil if the message is valid.
type Question ¶
type Question struct {
Name string `json:"name"`
Type uint16 `json:"type"`
Class uint16 `json:"class"`
}
Question represents a question in an LLMNR message.
An LLMNR (Link-Local Multicast Name Resolution) question consists of a domain name, a type, and a class. The domain name specifies the name being queried, while the type and class specify the type of the query (e.g., TypeA, TypeAAAA) and the class of the query (e.g., ClassIN), respectively.
Fields: - Name: The domain name being queried. - Type: The type of the query (e.g., TypeA, TypeAAAA). - Class: The class of the query (e.g., ClassIN).
The Question struct is used in the Questions section of an LLMNR message to represent individual questions being asked in the message. Each question is encoded and decoded using the EncodeQuestion and DecodeQuestion functions, respectively.
func DecodeQuestion ¶
DecodeQuestion decodes a byte slice into a Question struct.
This function takes a byte slice and an offset, and decodes the data starting from the offset into a Question struct. The domain name is decoded first, followed by the type and class fields. The function ensures that the data is not truncated and returns an error if any part of the decoding process fails.
Parameters: - data: A byte slice containing the encoded question in wire format. - offset: The starting position in the byte slice from which to begin decoding.
Returns:
- A Question struct containing the decoded data.
- An integer representing the new offset after decoding.
- An error if the decoding fails at any point, such as if the data is truncated or if there is an error decoding the domain name.
Usage:
question, newOffset, err := DecodeQuestion(data, offset)
if err != nil {
// handle error
}
The function returns the decoded Question struct, the new offset, and an error if any.
type ResourceRecord ¶
type ResourceRecord struct {
Name string `json:"name"`
Type uint16 `json:"type"`
Class uint16 `json:"class"`
TTL uint32 `json:"ttl"`
RDLength uint16 `json:"rdlength"`
RData []byte `json:"rdata"`
}
ResourceRecord represents a resource record in the LLMNR protocol.
A resource record is used to store information about a domain name, such as its IP address, mail server, or other related data. The ResourceRecord struct contains fields for the domain name, type, class, time-to-live (TTL), resource data length (RDLength), and resource data (RData).
Fields: - Name: The domain name associated with the resource record. - Type: The type of the resource record, indicating the kind of data stored (e.g., TypeA for IPv4 address). - Class: The class of the resource record, typically ClassIN for Internet. - TTL: The time-to-live value, indicating how long the record can be cached before it should be discarded. - RDLength: The length of the resource data in bytes. - RData: The resource data, which contains the actual information associated with the domain name (e.g., an IP address).
Usage example:
rr := ResourceRecord{
Name: "example.local",
Type: TypeA,
Class: ClassIN,
TTL: 300,
RDLength: 4,
RData: []byte{192, 168, 1, 1},
}
func DecodeResourceRecord ¶
func DecodeResourceRecord(data []byte, offset int) (ResourceRecord, int, error)
DecodeResourceRecord decodes a byte slice into a ResourceRecord struct. It expects the byte slice to be in the wire format as specified by the LLMNR protocol. The function first decodes the domain name, followed by the type, class, TTL, RDLength, and RData fields.
Parameters: - data: A byte slice containing the resource record in wire format. - offset: The starting position in the byte slice from which to begin decoding.
Returns:
- A ResourceRecord struct containing the decoded data.
- An integer representing the new offset position after decoding.
- An error if the decoding fails at any point, such as if the data is too short or if there is an error decoding the domain name.
Usage example:
data := []byte{...} // byte slice containing the resource record in wire format
offset := 0
rr, newOffset, err := DecodeResourceRecord(data, offset)
if err != nil {
log.Fatalf("Failed to decode resource record: %v", err)
}
Start Generation Here
type ResponseWriter ¶
ResponseWriter interface is used by an LLMNR handler to construct a response
func NewResponseWriter ¶
func NewResponseWriter(server *Server, remoteAddr net.Addr) ResponseWriter
NewResponseWriter creates a new ResponseWriter instance.
Parameters: - server: The Server instance that received the query. - remoteAddr: The address of the client that sent the query.
Returns: - A new ResponseWriter instance.
type Server ¶
type Server struct {
// Handlers is a slice of Handler interfaces that process incoming LLMNR messages.
Handlers []Handler
// Known networks are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only),
// "udp", "udp4" (IPv4-only), "udp6" (IPv6-only), "ip", "ip4"
// (IPv4-only), "ip6" (IPv6-only), "unix", "unixgram" and
// "unixpacket".
Network string
// Address is the address of the server.
Address *net.UDPAddr
// Conn is the connection of the server.
Conn *net.UDPConn
// CloseOnce is a sync.Once struct to ensure the server is closed only once.
CloseOnce sync.Once
// Closed is a channel that is closed when the server is shut down.
Closed chan struct{}
// Debug is a boolean flag indicating whether debug mode is enabled.
Debug bool
}
Server represents an LLMNR server.
The Server struct contains the necessary fields and methods to handle LLMNR (Link-Local Multicast Name Resolution) requests and responses. It supports both IPv4 and IPv6 communication over UDP.
Fields:
- Handlers: A slice of Handler interfaces that process incoming LLMNR messages.
- Network: A string representing the network type. Known networks are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only), "udp", "udp4" (IPv4-only), "udp6" (IPv6-only), "ip", "ip4" (IPv4-only), "ip6" (IPv6-only), "unix", "unixgram", and "unixpacket".
- Address: A pointer to a net.UDPAddr struct representing the server's address.
- Conn: A pointer to a net.UDPConn struct representing the server's UDP connection.
- CloseOnce: A sync.Once struct to ensure the server is closed only once.
- Closed: A channel that is closed when the server is shut down.
- Debug: A boolean flag indicating whether debug mode is enabled.
func NewIPv4Server ¶
NewIPv4Server creates a new LLMNR server for IPv4.
This function initializes a new Server instance configured to use the "udp4" network type for IPv4 communication. It does not accept any handlers and initializes the server with an empty list of handlers. The server's internal state, including the handlers, closed channel, and debug flag, is initialized.
Returns: - A pointer to the newly created Server instance. - An error if the server creation fails.
Example usage:
server, err := llmnr.NewIPv4Server()
if err != nil {
log.Fatalf("Failed to create IPv4 server: %v", err)
}
if server.IsIPv4() {
fmt.Println("The server is using an IPv4 address.")
} else {
fmt.Println("The server is not using an IPv4 address.")
}
func NewIPv4ServerWithHandlers ¶
NewIPv4ServerWithHandlers creates a new LLMNR server for IPv4 with the specified handlers.
This function initializes a new Server instance configured to use the "udp4" network type for IPv4 communication. It accepts a list of handlers that will be used to process incoming LLMNR requests. The server's internal state, including the handlers, closed channel, and debug flag, is initialized.
Parameters: - handlers: A slice of Handler instances to handle incoming LLMNR requests.
Returns: - A pointer to the newly created Server instance. - An error if the server creation fails.
Example usage:
handlers := []llmnr.Handler{
llmnr.HandlerFunc(myHandlerFunc),
}
server, err := llmnr.NewIPv4ServerWithHandlers(handlers)
if err != nil {
log.Fatalf("Failed to create IPv4 server: %v", err)
}
if server.IsIPv4() {
fmt.Println("The server is using an IPv4 address.")
} else {
fmt.Println("The server is not using an IPv4 address.")
}
func NewIPv6Server ¶
NewIPv6Server creates a new LLMNR server for IPv6.
This function initializes a new Server instance configured to use the "udp6" network type for IPv6 communication. It does not accept any handlers and initializes the server with an empty list of handlers. The server's internal state, including the handlers, closed channel, and debug flag, is initialized.
Returns: - A pointer to the newly created Server instance. - An error if the server creation fails.
Example usage:
server, err := llmnr.NewIPv6Server()
if err != nil {
log.Fatalf("Failed to create IPv6 server: %v", err)
}
if server.IsIPv6() {
fmt.Println("The server is using an IPv6 address.")
} else {
fmt.Println("The server is not using an IPv6 address.")
}
func NewIPv6ServerWithHandlers ¶
NewIPv6ServerWithHandlers creates a new LLMNR server for IPv6 with the specified handlers.
This function initializes a new Server instance configured to use the "udp6" network type for IPv6 communication. It accepts a list of handlers that will be used to process incoming LLMNR requests. The server's internal state, including the handlers, closed channel, and debug flag, is initialized.
Parameters: - handlers: A slice of Handler instances to handle incoming LLMNR requests.
Returns: - A pointer to the newly created Server instance. - An error if the server creation fails.
Example usage:
handlers := []llmnr.Handler{
llmnr.HandlerFunc(myHandlerFunc),
}
server, err := llmnr.NewIPv6ServerWithHandlers(handlers)
if err != nil {
log.Fatalf("Failed to create IPv6 server: %v", err)
}
if server.IsIPv6() {
fmt.Println("The server is using an IPv6 address.")
} else {
fmt.Println("The server is not using an IPv6 address.")
}
func NewServer ¶
NewServer creates a new LLMNR server with the specified network and handlers.
This function initializes a new Server instance with the provided network type and a list of handlers. The server is configured to use the specified network (e.g., "udp4" for IPv4, "udp6" for IPv6) and initializes its internal state, including the handlers, closed channel, and debug flag.
Parameters: - network: A string specifying the network type (e.g., "udp4", "udp6"). - handlers: A slice of Handler instances to handle incoming LLMNR requests.
Returns: - A pointer to the newly created Server instance. - An error if the server creation fails.
Example usage:
handlers := []llmnr.Handler{
llmnr.HandlerFunc(myHandlerFunc),
}
server, err := llmnr.NewServer("udp4", handlers)
if err != nil {
log.Fatalf("Failed to create server: %v", err)
}
if server.IsIPv4() {
fmt.Println("The server is using an IPv4 address.")
} else {
fmt.Println("The server is not using an IPv4 address.")
}
func (*Server) Close ¶
Close gracefully shuts down the LLMNR server by closing the UDP connection and signaling the server to stop. It ensures that the server is closed only once, even if Close is called multiple times.
The function uses a sync.Once to guarantee that the server's resources are released only once. It closes the server's closed channel to signal any goroutines to stop, and if the server has an active UDP connection, it closes the connection.
Returns: - An error if the server fails to close the UDP connection or encounters an error during the shutdown process.
Example usage: server, err := llmnr.NewServer(handler)
if err != nil {
log.Fatalf("Failed to create server: %v", err)
}
err = server.ListenAndServe()
if err != nil {
log.Fatalf("Server encountered an error: %v", err)
}
// When you want to stop the server err = server.Close()
if err != nil {
log.Fatalf("Failed to close server: %v", err)
}
func (*Server) IsIPv4 ¶
IsIPv4 checks if the server's address is an IPv4 address.
Returns: - A boolean value: true if the server's address is an IPv4 address, false otherwise.
The function uses the net.IP.To4 method to determine if the IP address is an IPv4 address. If the IP address is not an IPv4 address, the method will return nil, and the function will return false.
Example usage: server, err := llmnr.NewIPv4Server()
if err != nil {
log.Fatalf("Failed to create server: %v", err)
}
if server.IsIPv4() {
fmt.Println("The server is using an IPv4 address.")
} else {
fmt.Println("The server is not using an IPv4 address.")
}
func (*Server) IsIPv6 ¶
IsIPv6 checks if the server's address is an IPv6 address.
Returns: - A boolean value: true if the server's address is an IPv6 address, false otherwise.
The function uses the net.IP.To16 method to determine if the IP address is an IPv6 address. If the IP address is not an IPv6 address, the method will return nil, and the function will return false.
Example usage: server, err := llmnr.NewIPv6Server()
if err != nil {
log.Fatalf("Failed to create server: %v", err)
}
if server.IsIPv6() {
fmt.Println("The server is using an IPv6 address.")
} else {
fmt.Println("The server is not using an IPv6 address.")
}
func (*Server) ListenAndServe ¶
ListenAndServe starts the LLMNR server and begins listening for incoming UDP packets on the IPv4 multicast address. It creates a UDP connection and assigns it to the server's connection field. The function then enters a loop to continuously read from the UDP connection, decode incoming messages, and pass them to the server's handler.
Returns: - An error if the server fails to start listening on the UDP connection or encounters an error during execution.
Example usage: server, err := llmnr.NewServer(handler)
if err != nil {
log.Fatalf("Failed to create server: %v", err)
}
err = server.ListenAndServe()
if err != nil {
log.Fatalf("Server encountered an error: %v", err)
}
func (*Server) RegisterHandler ¶
RegisterHandler registers a new handler to the LLMNR server.
Parameters: - handler: The Handler to be registered. It must implement the Handler interface.
The function appends the provided handler to the server's list of handlers. These handlers will be invoked to process incoming LLMNR queries. Handlers are executed in the order they are registered.
Example usage:
handler := &MyHandler{}
server.RegisterHandler(handler)
This function is typically called before starting the server to ensure that all necessary handlers are in place to process incoming queries.
func (*Server) Serve ¶
Serve handles incoming LLMNR requests and processes them in a loop until the server is closed.
The function reads packets from the UDP connection, decodes the messages, and handles LLMNR queries. It uses a buffer to read the incoming packets and processes each packet in a separate goroutine.
The function also supports debugging, printing detailed information about the received packets and errors.
Returns: - An error if the server encounters an issue while reading from the UDP connection.
Example usage: server, err := llmnr.NewServer(handler)
if err != nil {
log.Fatalf("Failed to create server: %v", err)
}
err = server.ListenAndServe()
if err != nil {
log.Fatalf("Server encountered an error: %v", err)
}
// When you want to stop the server err = server.Close()
if err != nil {
log.Fatalf("Failed to close server: %v", err)
}
func (*Server) SetDebug ¶
SetDebug enables or disables debug mode for the LLMNR server.
Parameters: - debug: A boolean value indicating whether to enable (true) or disable (false) debug mode.
When debug mode is enabled, the server will print detailed information about incoming packets, decoded messages, and any errors encountered during processing. This can be useful for troubleshooting and understanding the server's behavior.
Example usage: server, err := llmnr.NewServer(handler)
if err != nil {
log.Fatalf("Failed to create server: %v", err)
}
server.SetDebug(true)
err = server.ListenAndServe()
if err != nil {
log.Fatalf("Server encountered an error: %v", err)
}