diff options
-rw-r--r-- | geoip/geoip.asd | 20 | ||||
-rw-r--r-- | geoip/ip.lisp | 59 | ||||
-rw-r--r-- | geoip/tests.lisp | 14 |
3 files changed, 44 insertions, 49 deletions
diff --git a/geoip/geoip.asd b/geoip/geoip.asd new file mode 100644 index 0000000..53826dd --- /dev/null +++ b/geoip/geoip.asd @@ -0,0 +1,20 @@ + +(defsystem "geoip" + :version "0.1.0" + :author "Oscar" + :license "GPL-3" + :depends-on ("cffi" + "mmap" + "split-sequence") + :components ((:file "ip")) + :description "Query maxminddb for ip information" + :in-order-to ((test-op (test-op "geoip/tests")))) + +(defsystem "geoip/tests" + :author "Oscar" + :license "GPL-3" + :depends-on ("geoip" + "fiveam") + :components ((:file "tests")) + :description "Test system for geoip" + :perform (test-op (op c) (symbol-call :fiveam :run!))) diff --git a/geoip/ip.lisp b/geoip/ip.lisp index a61989d..aae0702 100644 --- a/geoip/ip.lisp +++ b/geoip/ip.lisp @@ -1,21 +1,8 @@ ;;;; -*- mode: lisp -*- - -(ql:quickload '(cffi cffi-libffi split-sequence mmap ironclad babel nibbles fiveam local-time)) - (defpackage :geoip (:use :common-lisp :cffi :split-sequence)) -(in-package :geoip) - -(defun octet-to-int (seq &key (big-endian t)) - (reduce (lambda (acc n) - (+ (ash acc 8) n)) - (if big-endian - seq (reverse seq)) - :initial-value 0)) -(5am:test t-ints - (5am:is (= (octet-to-int '(1 5) :big-endian t) #x105)) - (5am:is (= (octet-to-int '(1 5) :big-endian nil) #x501))) +(in-package :geoip) (defun parse-ipv4 (ip-address) (reduce (lambda (acc n) @@ -38,15 +25,11 @@ (cons 4 (parse-ipv4 ip-address)) (cons 6 (parse-ipv6 ip-address)))) -(5am:test ipv4 - (5am:is (= (parse-ipv4 "8.8.8.8") 134744072)) - (5am:is (= (parse-ipv6 "::1") 1))) - (alexandria:define-constant +metadata-marker+ - (concatenate 'vector - #(#xab #xcd #xef) - (map 'vector #'char-code "MaxMind.com")) + (make-array 14 :element-type '(unsigned-byte 8) + :initial-contents + (list* #xab #xcd #xef (map 'list #'char-code "MaxMind.com"))) :test #'equalp) (defstruct maxmind-database @@ -93,15 +76,15 @@ :record-size (get-val data :record-size))) (defun metadata-marker-p (ptr offset) - (loop for i below #.(length *metadata-marker*) + (loop for i below #.(length +metadata-marker+) always (eql (mem-ref ptr :uchar (+ i offset)) - (svref *metadata-marker* i)))) + (aref +metadata-marker+ i)))) (defun find-metadata-start (ptr size) - (loop for offset from (- size 1 #.(length *metadata-marker*)) + (loop for offset from (- size 1 #.(length +metadata-marker+)) downto (- size 1 (* 128 1024)) when (metadata-marker-p ptr offset) - return (+ offset #.(length *metadata-marker*)))) + return (+ offset #.(length +metadata-marker+)))) (defun read-db-char (reader) (with-slots (db-ptr) reader @@ -139,15 +122,6 @@ (- uval #.(expt 2 32)) uval))) -(5am:test reader - (with-foreign-array (a #(0 0 1 23 126 195 159 195 156) '(:array :uint8 9)) - (let ((r (make-db-reader :db-ptr a))) - (5am:is (= 279 (mread-unsigned r 4))) - (5am:is (equal "~ßÜ" (mread-uft8 r 5)))))) - -(5am:run-all-tests) - - (defun mread-datafield-metadata (db-ptr) (let* ((control-byte (read-db-char db-ptr)) (type (ldb (byte 3 5) control-byte)) @@ -226,10 +200,9 @@ (defun record-value (mmdb ip-bits) (with-slots (node-count) mmdb - (loop with node = 0 + (loop for start = 0 then node for bit in ip-bits - for next-node = (read-node-record mmdb node bit) - do (setf node next-node) + for node = (read-node-record mmdb start bit) when (= node node-count) return nil when (> node node-count) @@ -272,15 +245,3 @@ (with-slots (ptr fd size) mmdb (mmap:munmap ptr fd size))) -(defvar *mmdb* (make-mmdb "GeoLite2-Country.mmdb")) - -(with-slots (metadata) *mmdb* - (with-slots (build-epoch) metadata - (local-time:unix-to-timestamp - build-epoch))) - -(lookup-ip *mmdb* (integer-to-bits (parse-ipv4 "28.8.8.8") 128)) -(lookup-ip *mmdb* (integer-to-bits (parse-ipv4 "89.244.127.3") 128)) -(lookup-ip *mmdb* (integer-to-bits (parse-ipv6 "2001:9e8:3d0f:2600:f081:c212:46c9:7cef") 128)) - - diff --git a/geoip/tests.lisp b/geoip/tests.lisp new file mode 100644 index 0000000..3aeebf7 --- /dev/null +++ b/geoip/tests.lisp @@ -0,0 +1,14 @@ +(defpackage geoip/tests + (:use :cl :cffi :fiveam :alexandria :geoip)) +(in-package :geoip/tests) + +(test ipv4 + (is (= (geoip::parse-ipv4 "8.8.8.8") 134744072)) + (is (= (geoip::parse-ipv6 "::1") 1))) + +(test reader + (with-foreign-array (a #(0 0 1 23 126 195 159 195 156) '(:array :uint8 9)) + (let ((r (geoip::make-db-reader :db-ptr a))) + (is (= 279 (geoip::mread-unsigned r 4))) + (is (equal "~ßÜ" (geoip::mread-uft8 r 5)))))) + |