DnsmasqログファイルのIPアドレスをそのホスト名に置き換えようとしています。ログファイルは、コンソールでコマンド「tail -f/var/log/dnsmasq.log」を使用して「監視」されています。出力をsedにパイプして、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"
'regex'は、文字列 "query"を含む行を識別し、その行の終わりからIPアドレスを抽出して、変数に(何らかの方法で)格納する必要があります-ここでは$1
という表記を使用しました-使用されています式をDigに置き換えます。
更新:IPアドレスは常に10.1.n.nの形式になることは言及しませんでした
残念ながら、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 ; \
}
このちょっと、sortaは機能します(ただし、「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/{...}正規表現 'query'に一致する行で{...}を実行します(他の文字を出力するだけです)
IP = $ NF新しい変数「IP」を行の最後のフィールドの値(IPアドレス)に設定します
$ NF = ""行の最後のフィールドをザップします
L = $新しい変数「L」を残りの行に設定します(つまり、IPアドレスなし)
"Host" IP | getline name IPアドレスで 'Host'を実行し、結果を新しい変数 'name'に入れます
$ 0 = name次のコマンドで$ NFを使用できるように、現在の行を「Host」コマンドからの出力に設定します。
print L、$ NF「L」(IPアドレスのない入力行)と「Host」コマンドの最後のフィールド(ホスト名)を出力します。
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'
_
これはシステムのネームサービスにクエリを実行しているため、おそらく_/etc/hosts
_、DNS、mDNS、LDAP、NIS + ...、またはシステムの_/etc/nsswitch.conf
_または同等のホスト名解決用に構成されているもので、おそらく名前を使用します。 nscd
やsssd
のようなサービスキャッシングサービス。同じIPアドレスを何度も照会しないように、キャッシングも実装しています。
4つの_.
_で区切られた10進数のシーケンスのみを照合し、他のIPv4アドレス形式は照合しませんが、inet_aton()
の場合、先頭の0は数値を8進数と見なすため、_010.010.010.010
_は実際には_8.8.8.8
_です(IPアドレスを引数として取るほとんどのものと同じですが、_Dig -x
_は取りません)。
Dig
のようにのみDNSサーバーにクエリを実行する必要がある場合は、gethostbyaddr()
の代わりに_Net::DNS
_を使用できます。
_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'
_