sedを使用して、ログ出力のIPアドレスをホスト名に置き換えます。

sedを使用して、ログ出力のIPアドレスをホスト名に置き換えます。

dnsmasqログファイルのIPアドレスをホスト名に置き換えようとしています。ログファイルは「tail -f /var/log/dnsmasq.log」コマンドを使用してコンソールで「監視」されており、出力をsedにパイプして「Query」を含む行でのみIPアドレスを置き換えようとします。ホスト名テキスト。 IPアドレスは常にこの行の末尾にあります。

例示的な行は次のとおりです。

Apr  1 00:47:43 dnsmasq[1004]: query[A] gs-loc.apple.com from 10.1.1.188

私はコマンドが次の形式であると思います。

tail -f /var/log/dnsmasq.log | sed -e "s/'regex'/$(dig +short -x $1)/g"

「正規表現」は、「query」文字列を含む行を識別し、行の末尾からIPアドレスを抽出して(とにかく)変数に保存する必要があります。$1ここでは表記法を使用しました。置換式digに使用されました。

更新:IPアドレスが常に10.1.nn形式であることに言及できませんでした。

答え1

残念ながら、sed 入力から取得した引数を渡しながら外部コマンドを実行することはできません。

以下はBashスクリプトソリューションです。

tail -f dnsmasq.log | { while IFS= read -r line ; do { [[ "${line}" =~ ": query[A]" ]] && printf '%s %s\n' "${line% *} " $(dig +short -x "${line##* }"); } || echo "${line}"; done ; }

分解の説明:(わかりやすくするためにコピーして貼り付けると機能しない可能性があります。)

tail -f dnsmasq.log | \
    { \
        while IFS= read -r line ; do \           # for each line read in from tail ...
            if [[ "${line}" =~ ": query[A]" ]] ; # if it has the literal string ': query[A]'
            then \
                printf '%s %s\n' "${line% *} " \ # print it (purged of last field, which is the IP address) ...
                $(dig +short -x "${line##* }") \ # along with dig's output
            else \                               # otherwise ...
                echo "${line}" \                 # just print it all as it is
            fi \
        done ; \
    }

答え2

これはある程度動作します(ただし、「sed」の代わりに「awk」を使用します):

$ echo $'Apr  1 00:47:43 dnsmasq[1004]: query[A] gs-loc.apple.com from 8.8.8.8' | awk '/query/{ IP=$NF; $NF=""; L=$0; "host " IP | getline name; $0=name; print L,$NF }'
Apr 1 00:47:43 dnsmasq[1004]: query[A] gs-loc.apple.com from  google-public-dns-a.google.com.

...いくつかの改善が必要です(たとえば、ホストの検索に失敗した場合は、正規表現「クエリ」がより具体的である必要があるかもしれません)。

以下は、awk コマンドの説明です。

/尋ねる/ { ... }正規表現「query」に一致する行で{...}を実行します(他の行のみを印刷)。

IP=$NF新しい変数「IP」を行の最後のフィールド値(IPアドレス)に設定します。

$NF=""zap行の最後のフィールド

L=$0新しい変数「L」を残りの行(つまりIPアドレスなし)に設定します。

「ホスト」IPライン名を取得|IP アドレスで "host" を実行し、結果を新しい変数 "name" に入れます。

$0=名前次のコマンドで$ NFを使用できるように、現在の行を "host"コマンドの出力に設定します。

印刷L、$ NF「L」(IPアドレスのない入力行)と「host」コマンドの最後のフィールド(ホスト名)を印刷します。

答え3

各 IP アドレスに対して実行することはdig非常に非効率的で、DNS サーバーの負荷を増加させます。ここでは以下を使用しますperl

perl -MSocket -pe 's{(?<![\d.])\d+\.\d+\.\d+\.\d+(?![\d.])}{
    $ip = inet_aton($&);
    $cache{$ip} //= gethostbyaddr($ip,AF_INET) // "UNKNOWN[$&]"
  }ge'

これはシステムのネームサービスを照会するため、DNS、mDNS、LDAP、NIS+...、またはネーム/etc/hostsサービスキャッシュサービスを介してホスト名解決またはそれに対応するシステムで構成されているすべてのものにすることができます。また、同じIPアドレスを複数回照会することを防ぐために実装されています。/etc/nsswitch.confnscdsssd

.他のIPv4アドレス形式ではなく、4つの別々の10進数シーケンスのみを一致させます。しかし、 のinet_aton()場合、前に0があれば数字が8進数として扱われるので、010.010.010.010実際には8.8.8.8IPアドレスを主張するがdig -x)。

このようにDNSサーバーへの照会に必要な場合は、次のものを使用digできます。Net::DNSgethostbyaddr()

perl -MNet::DNS -pe '
  sub resolve {
    my ($r) = rr($_[0]);
    if (defined($r)) {
      return $r->ptrdname;
    } else {
      return "UNKNOWN[$_[0]]";
    }
  }
  s{(?<![\d.])\d+\.\d+\.\d+\.\d+(?![\d.])}{$cache{$&} //= resolve $&}ge'

関連情報