summaryrefslogtreecommitdiff
path: root/src/client.lisp
diff options
context:
space:
mode:
authorsoukev <soukev@soukev.xyz>2026-06-06 20:07:02 +0200
committersoukev <soukev@soukev.xyz>2026-06-06 20:07:02 +0200
commit8a62a3f1f60521082bdb5c27be6d7246ebf12306 (patch)
tree8f1712eb430f9a3442a74e361000aa44f42c7ea0 /src/client.lisp
parent1b05818535abdda01a2bbe8aacd8f535c5c7c74c (diff)
Project kick-off
Diffstat (limited to 'src/client.lisp')
-rw-r--r--src/client.lisp48
1 files changed, 48 insertions, 0 deletions
diff --git a/src/client.lisp b/src/client.lisp
new file mode 100644
index 0000000..fd0b581
--- /dev/null
+++ b/src/client.lisp
@@ -0,0 +1,48 @@
+(defpackage :cl-mdns/client
+ (:use :cl
+ :cl-mdns/packet)
+ (:local-nicknames (:nb :nibbles)
+ (:f :fsocket))
+ (:export :lookup))
+(in-package :cl-mdns/client)
+
+(defvar *mdns-address* #(224 0 0 251))
+(defvar *mdns-port* 5353)
+
+(defun parse-ipv4-response (packet)
+ "Extracts the first IPv4 address found in a DNS response packet."
+ (let* ((qdcount (+ (ash (aref packet 4) 8) (aref packet 5)))
+ (ancount (+ (ash (aref packet 6) 8) (aref packet 7)))
+ (pos 12)) ; Start after header
+
+ ;; Skip Question section
+ (loop repeat qdcount do
+ (loop while (not (zerop (aref packet pos)))
+ do (incf pos (1+ (aref packet pos))))
+ (incf pos 5)) ; Skip null byte + Type(2) + Class(2)
+
+ ;; Parse Answer section
+ (if (> ancount 0)
+ (let ((type (+ (ash (aref packet (+ pos 2)) 8) (aref packet (+ pos 3))))
+ ;(rdlen (+ (ash (aref packet (+ pos 10)) 8) (aref packet (+ pos 11))))
+ )
+ ;; If Type is 1 (A record), return the next 4 bytes as an IP string
+ (if (= type 1)
+ (format nil "~D.~D.~D.~D"
+ (aref packet (+ pos 12)) (aref packet (+ pos 13))
+ (aref packet (+ pos 14)) (aref packet (+ pos 15)))
+ "Non-IPv4 record received"))
+ "No answers found")))
+
+(defun lookup (domain)
+ (let ((fd (f:open-socket :type :datagram))
+ (packet (build-query-packet domain))
+ (buffer (make-array 512 :element-type '(unsigned-byte 8))))
+ (unwind-protect
+ (progn
+ (f:socket-bind fd (f:make-sockaddr-in))
+ (f:socket-sendto fd packet (f:make-sockaddr-in :addr *mdns-address* :port *mdns-port*))
+ (multiple-value-bind (count raddr) (f:socket-recvfrom fd buffer)
+ (declare (ignore raddr))
+ (parse-ipv4-response (subseq buffer 0 count))))
+ (f:close-socket fd))))