-
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathtoolkit.lisp
127 lines (118 loc) · 4.87 KB
/
toolkit.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
(in-package #:org.shirakumo.dns-client)
(define-condition dns-condition ()
())
(define-condition dns-server-failure (error dns-condition)
((dns-server :initarg :dns-server :reader dns-server)
(response-code :initarg :response-code :reader response-code))
(:report (lambda (c s) (format s "DNS server ~% ~a~%responded with failure code ~d~@[~% ~a~]"
(dns-server c) (response-code c) (response-code-name (response-code c))))))
(define-condition dns-servers-exhausted (error dns-condition)
()
(:report (lambda (c s) (format s "All DNS servers failed to provide an answer for the query."))))
(defun response-code-name (code)
(case code
(0 :success)
(1 :format-error)
(2 :server-failure)
(3 :no-such-domain)
(4 :not-implemented)
(5 :query-refused)
(6 :name-should-not-exist)
(7 :set-should-not-exist)
(8 :set-does-not-exist)
(9 :not-authorized)
(10 :not-in-zone)
(11 :type-not-implemented)
(16 :bad-version)
(17 :key-not-recognised)
(18 :bad-time)
(19 :bad-mode)
(20 :duplicate-key)
(21 :bad-algorithm)
(22 :bad-truncation)
(23 :bad-cookie)))
(defmacro with-dns-error-handling (&body body)
`(handler-bind ((dns-server-failure
(lambda (e)
(unless (find (response-code e) '(1 3 6 7 8))
(continue e)))))
,@body))
;;; Note: we assume that we never cross byte boundaries when accessing bits.
(defmacro with-decoding ((octets start &optional (pos (gensym "POS"))) &body body)
`(let ((,pos ,start))
(flet ((int1 ()
(prog1 (logbitp (* 8 (rem ,pos 1)) (aref ,octets (floor ,pos)))
(incf ,pos 1/8)))
(int4 ()
(prog1 (ldb (byte 4 (* 8 (rem ,pos 1))) (aref ,octets (floor ,pos)))
(incf ,pos 4/8)))
(int8 ()
(prog1 (aref ,octets (floor ,pos))
(incf ,pos 1)))
(int16 () ;; big-endian
(prog1 (+ (ash (aref ,octets (+ 0 (floor ,pos))) 8)
(ash (aref ,octets (+ 1 (floor ,pos))) 0))
(incf ,pos 2)))
(int32 ()
(prog1 (+ (ash (aref ,octets (+ 0 (floor ,pos))) 24)
(ash (aref ,octets (+ 1 (floor ,pos))) 16)
(ash (aref ,octets (+ 2 (floor ,pos))) 8)
(ash (aref ,octets (+ 3 (floor ,pos))) 0))
(incf ,pos 4))))
(declare (ignorable #'int1 #'int4 #'int8 #'int16 #'int32))
,@body)))
(defmacro with-encoding ((octets start &optional (pos (gensym "POS"))) &body body)
`(let ((,pos ,start))
(flet ((int1 (value)
(let ((octet (aref ,octets (floor ,pos))))
(setf (ldb (byte 1 (* 8 (rem ,pos 1))) octet)
(ecase value
((0 1) value)
((T) 1)
((NIL) 0)))
(setf (aref ,octets (floor ,pos)) octet)
(incf ,pos 1/8)))
(int4 (value)
(let ((octet (aref ,octets (floor ,pos))))
(setf (ldb (byte 4 (* 8 (rem ,pos 1))) octet) value)
(setf (aref ,octets (floor ,pos)) octet)
(incf ,pos 4/8)))
(int8 (value)
(setf (aref ,octets (floor ,pos)) value)
(incf ,pos 1))
(int16 (value) ;; big-endian
(setf (aref ,octets (+ 0 ,pos)) (ldb (byte 8 8) value))
(setf (aref ,octets (+ 1 ,pos)) (ldb (byte 8 0) value))
(incf ,pos 2))
(int32 (value) ;; big-endian
(setf (aref ,octets (+ 0 ,pos)) (ldb (byte 8 24) value))
(setf (aref ,octets (+ 1 ,pos)) (ldb (byte 8 16) value))
(setf (aref ,octets (+ 2 ,pos)) (ldb (byte 8 8) value))
(setf (aref ,octets (+ 3 ,pos)) (ldb (byte 8 0) value))
(incf ,pos 4)))
(declare (ignorable #'int1 #'int4 #'int8 #'int16 #'int32))
,@body)))
(defmacro maybe-set ((octets offset) &body calls)
`(with-encoding (,octets ,offset pos)
,@(loop for (func value) in calls
collect `(if ,value
(,func ,value)
(incf pos ,(ecase func
(int1 1/8)
(int4 4/8)
(int8 1)
(int16 2)
(int32 4)))))
pos))
(defun split (on string)
(let ((parts ())
(buffer (make-string-output-stream)))
(flet ((finish ()
(let ((buffer (get-output-stream-string buffer)))
(push buffer parts))))
(loop for char across string
do (if (char= on char)
(finish)
(write-char char buffer))
finally (finish)))
(nreverse parts)))