Comment detail

アクセスログのIPアドレスを逆引き (Nested Flatten)
手抜きをして名前解決は外部コマンドのdigを使っています(あと出力結果を整形するためにawkも)。

一応特徴としては、
(1) スレッドを使うと排他とか面倒なので、プロセスで並列に動かしている
(2) ログを置換するフィルタプロセスと名前解決のプロセスの両方が並列に動作する
    (さらに名前解決のプロセスはdigを並列で実行する)
(3) 名前解決のプロセスも自分で勝手にファイルをスキャンしてIPアドレスを抜き出している。
    ファイルI/Oは通常の2倍になるが、フィルタプロセスとの相互作用が一方通行になるので作りは簡単になる。

実行は gosh resolv-filter.scm access.logのようにしてください。
max-processesをいじるとdigの同時実行数が変更できます。
 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
(use gauche.process)
(use srfi-13)

(define max-processes 4)

(define (filter log-port resolver-port)
  (let ((tbl (make-hash-table 'string=?)))
    (define (resolv addr)
      (or (hash-table-get tbl addr #f)
          (begin
            (apply hash-table-put! tbl (read resolver-port))
            (resolv addr))))
    (port-for-each (lambda (line)
                     (print (regexp-replace #/^\d+\.\d+\.\d+\.\d+/ line
                                            (lambda (m)
                                              (resolv (m))))))
                   (cut read-line log-port))))

(define (resolver log-port resolver-port)
  (define (notify! nohang)
    (and-let* ((proc (process-wait-any nohang)))
      (write (string-split (string-trim-right (port->string (process-output proc))
                                              #[\x0d\x0a]) " ") resolver-port)
      (flush resolver-port)))
  (let ((tbl (make-hash-table 'string=?)))
    (port-for-each (lambda (line)
                     (rxmatch-if (#/^(\d+\.\d+\.\d+\.\d+)/ line) (addr)
                       (unless (hash-table-exists? tbl addr)
                         (hash-table-put! tbl addr #t)
                         (run-process `("/bin/sh" "-c" ,#`"dig -x ,addr | awk 'BEGIN{f=0}/^[0-9].*[\t ]PTR/&&f==0{sub(/\.$/,,\"\",,$5);print \",addr\",,$5;f=1}END{if(f==0)print \",addr\",,\",addr\"}'")
                                      :output :pipe))
                       #f)
                     (notify! (< (length (process-list)) max-processes)))
                   (cut read-line log-port))
    (do () ((not (notify! #f))))))

(define (main args)
  (let ((filename (list-ref args 1)))
    (receive (in out) (sys-pipe)
      (if (= (sys-fork) 0)
          (call-with-input-file filename
            (cut resolver <> out))
          (call-with-input-file filename
            (cut filter <> in)))))
  0)

Index

Feed

Other

Link

Pathtraq

loading...