aboutsummaryrefslogtreecommitdiffstats
path: root/geoip/ip.lisp
diff options
context:
space:
mode:
authorOscar Najera <hi@oscarnajera.com>2025-06-07 11:12:16 +0200
committerOscar Najera <hi@oscarnajera.com>2025-06-07 11:17:52 +0200
commit8e7ba500330f81d187bb14284ba90144e32195f0 (patch)
treee802e3ab113468e097b505a61c4eca821c27321d /geoip/ip.lisp
parent17f03d92e1e01c381e0f6f4421f653b67ab0819a (diff)
downloadscratch-8e7ba500330f81d187bb14284ba90144e32195f0.tar.gz
scratch-8e7ba500330f81d187bb14284ba90144e32195f0.tar.bz2
scratch-8e7ba500330f81d187bb14284ba90144e32195f0.zip
Refactor and export symbols
Diffstat (limited to 'geoip/ip.lisp')
-rw-r--r--geoip/ip.lisp50
1 files changed, 30 insertions, 20 deletions
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)))