技術メモ

神奈川在住のITエンジニアの備忘録。おもにプログラミングやネットワーク技術について、学んだことを自分の中で整理するためにゆるゆると書いています。ちゃんと検証できていない部分もあるのでご参考程度となりますが、誰かのお役に立てれば幸いです。

HP-UXサーバ上のネットワーク・インターフェースの情報を確認する

HP-UXサーバ上で、当該サーバが持つネットワーク・インターフェースの情報を表示するには、

  netstat -in 

を実行する。

他の UNIX OS のように、

  ifconfig -a

を実行しても、ネットワーク・インターフェースの情報は表示されない (というかエラーになる)。

 

【参考】

https://community.hpe.com/t5/Networking/ifconfig-a-not-working-on-HP-UX-why/td-p/5956157#.XA_M1Gj7SUk

C言語を習い始めた頃に躓いたところ

最近、久々にC言語で書かれたプログラムのソース解析を行う機会があった。(普段はJavaperl がメイン。)

少し懐かしくなったので、主題の件についてちょっと書こうと思う。

 

  • static 修飾子の意味が使う場所によって変わる。

関数内で変数に対して使用すれば、関数が終わっても値を保持する変数となる。一方、関数外でグローバル変数に対して使用すれば、そのソースファイルからしか参照できない変数となる。

 

  • extern 修飾子は何者?

実体(定義)は他のソースファイルにあることを意味する。コンパイルの際は、1ファイルずつ処理されるので、他のソースファイルのグローバル変数を何も考えず参照すると、コンパイルエラーとなる。これに対して extern 修飾子を付けると、コンパイラは「他のソースファイルで定義されているから、ここは気にしない」としてエラーにならない。extern 変数はリンク時に解決される。

 

  • 関数内で変数定義する場合、普通に定義してスタック領域に確保すべきか、mallocしてヒープ領域に確保すべきか?

関数内で一時的に使用する変数の場合、スタック領域に確保する。関数が終わった後もしばらく使う場合は、ヒープ領域に確保する。なお、ヒープ領域に確保した場合、必要なくなった時に解放しないとメモリリークになるので要注意。

 

他にもいろいろ躓いたと思うのだが、もう十数年前なのでイマイチ思い出せない(苦笑) ちなみに、定番のはまりポイントと言われる「ポインタ」については、「実体へのメモリアドレスが入っている変数」くらいにシンプルに考えて、あまり躓かなかった。

SNMPのメッセージフォーマット

SNMPのメッセージフォーマットについて、分かりやすく説明しているページを幾つか見つけたので、あとで見返すためにここにメモしておく。

SNMP: Simple? Network Management Protocol

SNMPとは | IT用語 | 意味 解説

 

上の方のページは英文だが、SNMPのメッセージフォーマットにはどのような規約が用いられているのかも分かりやすく説明されている。

ざっくり言うと、SNMPのメッセージフォーマットは ASN.1 (Abstract Syntax Notation One) に従っており、さらに ASN.1 に含まれる BER (Basic Encoding Rules) にも従っている。

コミュニティ ストリング インデックスについて

Cisco の機器に対して SNMP で MIB 情報を取得する際の、「コミュニティ ストリング インデックス」について勉強した。

SNMP コミュニティ ストリング インデックス - Cisco

 

簡単に纏めると、例えば、機器が vlan 100 を持っているとして、機器から SNMP で vlan 100 のMIB 情報を取得するには、「コミュニティ名@100」で SNMP 要求を行う必要があるということ。「コミュニティ名」だけで SNMP 要求を行うと、vlan 情報は vlan 1 のものしか取得できないらしい。

つまり、Cisco機器が持っている(vlan1以外の) vlan の MIB 情報を SNMP で取得するために、コミュニティ ストリング インデックスは必要ということだと思う。

Javaの名前解決のキャッシュ

Javaの名前解決では、以下のようにキャッシュを使っているので、OS(hosts)やDNSで名前解決を変更しても、すぐに反映されるわけではない。

networkaddress.cache.ttl
java.securityで指定して、ネーム・サービスからの名前の検索に成功した場合のキャッシング・ポリシーを示します。指定する値は、成功した検索結果をキャッシュする秒数を示す整数です。-1の値は、「ずっとキャッシュする」という意味です。デフォルトでは、セキュリティ・マネージャがインストールされている場合はずっとキャッシュし、セキュリティ・マネージャがインストールされていない場合は実装固有の期間キャッシュします。

ネットワークのプロパティ


上記ページに「セキュリティ・マネージャがインストールされていない場合は実装固有の期間キャッシュします。」とあるが、実際にどれくらい名前解決のキャッシュを保持するのか調べてみた。

手元にあるJava8の java.security ファイルを見てみる。

#
# The Java-level namelookup cache policy for successful lookups:
#
# any negative value: caching forever
# any positive value: the number of seconds to cache an address for
# zero: do not cache
#
# default value is forever (FOREVER). For security reasons, this
# caching is made forever when a security manager is set. When a security
# manager is not set, the default behavior in this implementation
# is to cache for ★30 seconds.
#
# NOTE: setting this to anything other than the default value can have
# serious security implications. Do not set it unless
# you are sure you are not exposed to DNS spoofing attack.
#
#networkaddress.cache.ttl=-1

上記によると、キャッシュの保持時間は30秒と読み取れる。念のため、少し実機検証してみる。

実機検証に使ったプログラムは以下。

import java.net.InetAddress;
import java.net.UnknownHostException;

public class NameResolveSample {
    public static void main(String[] args) {
        String hostname = "www.test.local";
        String ipAddress = "192.168.100.10";
        int timeToWait = 35*1000; // ms
        try {
            String result1 = getIPaddrFromHostname(hostname);
            System.out.println("Hostname to ip address: " + result1);
            String result2 = getHostnameFromIPaddr(ipAddress);
            System.out.println("IP address to hostname: " + result2);

            // Change name resolution for test.
            //    192.168.100.10  www.test.local
            // -> 192.168.100.10  www.test1.local
            System.out.println("Waiting " + timeToWait/1000 + " seconds. Change name resolution(in hosts etc...) during this period.");
            Thread.sleep(timeToWait);

            String result3 = getIPaddrFromHostname(hostname);
            System.out.println("Hostname to ip address: " + result3);
            String result4 = getHostnameFromIPaddr(ipAddress);
            System.out.println("IP address to hostname: " + result4);
        }
        catch (Exception ex){
            System.out.println(ex.getMessage());
            System.out.println(ex.getStackTrace());
        }
    }

    private static String getIPaddrFromHostname (String hostname) {
        InetAddress ia;
        try {
            ia = InetAddress.getByName(hostname);
        }
        catch (UnknownHostException ex) {
            System.out.println("Can't resolve " + hostname);
            return hostname;
        }
        byte[] octets = ia.getAddress();
        StringBuffer ipStr = new StringBuffer();
        for (byte octet : octets) {
            ipStr.append(Integer.toString(octet & 0xff)); // https://akrad.hatenablog.com/entry/2018/04/09/222238
            ipStr.append('.');
        }
       return stripEnd(ipStr.toString());
    }

    private static String stripEnd (String str) {
        if (str != null && str.length() > 0) {
            str = str.substring(0, str.length()-1);
        }
        return str;
    }

    private static String getHostnameFromIPaddr (String ipaddr) {
        InetAddress ia;
        try {
            ia = InetAddress.getByName(ipaddr);
        }
        catch (UnknownHostException ex) {
            System.out.println("Can't resolve " + ipaddr);
            return ipaddr;
        }
        String fqdn = ia.getCanonicalHostName();
        return fqdn;
    }
}

これを timeToWait を変更しながら実行してみたところ、以下の結果になった。

〇1回目の名前解決から2回目の名前解決まで25秒(30秒以内)。
Hostname to ip address: 192.168.100.10
IP address to hostname: www.test.local
Waiting 25 seconds. Change name resolution during this period.
Hostname to ip address: 192.168.100.10
IP address to hostname: www.test1.local


〇1回目の名前解決から2回目の名前解決まで35秒(30秒以上)。
Hostname to ip address: 192.168.100.10
IP address to hostname: www.test.local
Waiting 35 seconds. Change name resolution during this period.
Can't resolve www.test.local
Hostname to ip address: www.test.local
IP address to hostname: www.test1.local

名前解決(正引き)の方は、予想通り、30秒以内であればキャッシュの結果が返るようだ。一方で、名前解決(逆引き)の方は、その都度の結果が返っており、キャッシュが使用されていないように見える。
この辺りは、今後 InetAddress クラスのソースを読んで仕様を確かめてみたい。

perl で外部コマンドの戻り値を取得する。

perl のsystem関数を使って外部コマンドを実行する時、外部コマンドの戻り値を取得するには、ちょっと注意が必要。

Perlの組み込み関数 system の翻訳 - perldoc.jp

返り値は、wait が返すプログラムの exit 状態です。 実際の exit 値を得るには 右に 8 ビットシフトしてください

上記perldocの通り、外部コマンドの戻り値を取得するには、system関数が返した値を右に 8 ビットシフトする必要がある。
以下にテストスクリプトとその結果を示す。

use strict;
use warnings;

my $rc = system("test.bat"); # test.bat (外部コマンド)は 1 を返す。
print "Return code = $rc\n"; # rcは 256 になる。

$rc = $rc >> 8; # ★8bit右にシフト
print "Return code = $rc\n"; # rcは 1 になる。これは外部コマンドの本当の戻り値。

icmpパケットのIDとシーケンス番号

icmpパケットには、ID(Identifier) と シーケンス番号(Sequence Number) が含まれている。これらがどのように使用されるのかイマイチ分かっていなかったので、ちょっと調べてみた。いつも通り、大正義 rfc を見に行く。すると、

https://tools.ietf.org/html/rfc792

に、以下の記載を見つけた。

The identifier and sequence number may be used by the echo sender
to aid in matching the replies with the echo requests. For
example, the identifier might be used like a port in TCP or UDP to
identify a session, and the sequence number might be incremented
on each echo request sent. The echoer returns these same values
in the echo reply.

Identifier と Sequence Number は、icmpリクエストを送信した側が要求パケットと応答パケットとを紐付けるために使用されるかもしれないとあり、rfc として使い方を規定しているわけではない。なお、icmpリクエストを受信したら、その応答には同じ Identifier と Sequence Number を入れるとある。

 

つまり、rfc としては、

「icmpリクエストを受信した時は、Identifier と Sequence Number にリクエストと同じ値を入れて応答してね。」

ということを規定しているくらいで、icmpリクエスト送信時に Identifier と Sequence Number に何を入れるのかは自由のように読める。

rfc の「For example・・」にあるように、Identifier は icmpリクエストを送ったプロセスを識別するものとして、Sequence Number は各 icmp 要求と応答を紐付けるものとして、使用するのが多いのだろうか。