From 8e7ba500330f81d187bb14284ba90144e32195f0 Mon Sep 17 00:00:00 2001 From: Oscar Najera Date: Sat, 7 Jun 2025 11:12:16 +0200 Subject: Refactor and export symbols --- geoip/ip.lisp | 50 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 20 deletions(-) (limited to 'geoip/ip.lisp') diff --git a/geoip/ip.lisp b/geoip/ip.lisp index d97f5c2..2b69233 100644 --- a/geoip/ip.lisp +++ b/geoip/ip.lisp @@ -1,9 +1,16 @@ ;;;; -*- mode: lisp -*- (defpackage :geoip - (:use :common-lisp :cffi :split-sequence)) + (:use :common-lisp :cffi :split-sequence) + (:export + :get-in :parse-ip :query-ip + :make-mmdb :close-mmdb :with-mmdb)) (in-package :geoip) +(defun get-in (data &rest keys) + "Get nested value from alist/map structure" + (reduce (lambda (acc key) (cdr (assoc key acc :test #'equal))) keys :initial-value data)) + (defun parse-ipv4 (ip-address) (reduce (lambda (acc n) (assert (<= 0 n 255)) @@ -60,20 +67,17 @@ (description nil :read-only t :type list)) -(defun get-val (alist key &key (test #'equal)) - (cdr (assoc key alist :test test))) - (defun make-metadata (data) (make-maxmind-database-metadata - :binary-format-major-version (get-val data :binary-format-major-version) - :binary-format-minor-version (get-val data :binary-format-minor-version) - :build-epoch (get-val data :build-epoch) - :database-type (get-val data :database-type) - :description (get-val data :description) - :ip-version (get-val data :ip-version) - :languages (get-val data :languages) - :node-count (get-val data :node-count) - :record-size (get-val data :record-size))) + :binary-format-major-version (get-in data :binary-format-major-version) + :binary-format-minor-version (get-in data :binary-format-minor-version) + :build-epoch (get-in data :build-epoch) + :database-type (get-in data :database-type) + :description (get-in data :description) + :ip-version (get-in data :ip-version) + :languages (get-in data :languages) + :node-count (get-in data :node-count) + :record-size (get-in data :record-size))) (defun metadata-marker-p (ptr offset) (loop for i below #.(length +metadata-marker+) @@ -207,20 +211,26 @@ when (> node node-count) return node))) -(defun lookup-ip (mmdb ip-bits) - (alexandria:when-let ((record (record-value mmdb ip-bits))) - (with-slots (ptr data-offset node-count) mmdb +(defun lookup-ip-bits (mmdb ip-bits) + (with-slots (ptr data-offset node-count) mmdb + (alexandria:when-let* ((record (record-value mmdb ip-bits)) + (offset (+ data-offset (- record node-count 16)))) (mread-data - (make-db-reader - :db-ptr (inc-pointer ptr (+ data-offset (- record node-count 16))) - :head-ptr ptr - :data-offset data-offset))))) + (make-db-reader :db-ptr (inc-pointer ptr offset) + :head-ptr ptr :data-offset data-offset))))) (defun integer-to-bits (n bit-count) "Convert integer to list of bits (MSB first)" (loop for i from (1- bit-count) downto 0 collect (if (logbitp i n) 1 0))) +(defun query-ip (mmdb ip-string) + (destructuring-bind (ip-v . ip-val) (parse-ip ip-string) + (with-slots (ip-version) mmdb + (when (and (= ip-version 4) (= ip-v 6)) + (error "Can't query IPv6 address in IPv4 database")) + (lookup-ip-bits mmdb (integer-to-bits ip-val (if (= ip-version 4) 32 128)))))) + (defun mmap->mmdb (file ptr fd size) (let* ((metadata-start (find-metadata-start ptr size)) (db-reader (make-db-reader :db-ptr (inc-pointer ptr metadata-start))) -- cgit v1.2.3