C MAGAZINE Linux programming Tips
第1回 ifconfigもどき (ifc-modoki) を作ってみよう
■はじめに
唐突に、「ifconfigもどきを作ってみよう」と言われても多くの読者の方々は、 「そんなあるもん作ってどうすんの?」という反応があるかもしれま せんが("ifconfigって何?"という人はいませんよね?)、Linuxプログ ラミングに慣れるためにも挑戦してみてください。
ちなみに、ifconfigもどきが作れるようになっても、応用分野としては、 Linuxのインストーラやネットワーク設定ツールの開発ぐらいなのであまり幸せになれませんが、 ifconfigもどきを切口にしてsocket()関数や IPアドレスの扱いやLinuxのprocファイルシステムなどに慣れると言う意味では修行の一貫になるはずです。
■基本アイディア
ifconfigもどきの基本アイディアは、簡単です。まずsocket()関数で Linuxカーネルとお話しする準備をして、ioctl()関数でネットワークイ ンターフェイスの制御をするだけです。「では、ここで話しは終り、あ とはソースコード(
リスト1)を見といて 」と言いたいところですが、あまりに無責任なので話を続けます。
■仕様
ifconfigもどき(ifc-modoki)は、ifconfigから大幅に機能を削減したものと考えてください。 とりあえずifc-modokiのコマンドライン仕様を説 明しますので、 まずはifc-config.cをコンパイルして以下の説明に従って動作を確認してください。
ifc-modokiに何も引数を指定しなかった場合や、第一引数にインタフェイス名だけを指定した場合は、 インターフェイスの情報(一覧)を表示し ます。
# ifc-modoki eth0
eth0 inet addr:192.168.0.10 Bcast:192.168.0.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST
|
インターフェイスにIPアドレスを指定する場合は、第一引数にインター フェイス名、第二引数にIPアドレスを指定します。 またマスクアドレス の指定は、ifconfigより少し賢くして、IPアドレスあとに/マスクビット数を 指定できるようになっています。
ifc-modokiに何も引数を指定しなかった場合や、第一引数にインタフェイス名だけを指定した場合は、 インターフェイスの情報(一覧)を表示します。
# ifc-modoki eth0 192.168.0.10/25
IPアドレスの代わりに、upまたはdownを指定すると、そのインターフェイスを有効したり無効にしたりできます。
# ifc-modoki eth0 down
■ソースコードの説明
ifc-modokiのソースコード(
リスト1)の流れ自体はそれほど複雑なものでないのでmain()関数から眺めて行けば理解できるはずです。 ソースコードの関数ごとの説明は、今回省きます。 その代わりにソースコードを理解をしやすくするための要点(基本構造,使用可能なインターフェイスの取得,IPアドレスの扱い)のみの説明にさせて頂きます。
基本構造
前述したように、ifc-modokiは、socket()関数によりカーネルとのエンドポイントを確立し、 ioctl()関数によりインターフェイス(デバイス)のパラメータを操作します。 ifc-modokiの基本構造を簡単に説明するために以下の例を用意しました。
int netDeviceAvailable(char *device)
{
struct ifreq req;
int s;
s = socket(AF_INET, SOCK_DGRAM, 0);
if(s < 0) {
perror( "Socket Error!\n");
close(s);
return FAILURE;
}
strcpy(req.ifr_name, device);
if (ioctl(s, SIOCGIFFLAGS, &req)) {
close(s);
return SUCCESS;
}
return FAILURE;
}
|
netDeviceAvailable()関数は、その名の通り(指定された)デバイスが有効であるかどうか調べるための関数です。 SIOCGIFFLAGSリクエストを発行して、 リクエストが受け付けられるかどうかでデバイスが有効か判断しています。SIOCGIFFLAGSリクエストを発行して成功した場合は、 req.ifr_flagsに デバイスの状態フラグが代入されます。
今回、リスト1で使用しているパラメータ取得とパラメータ設定のためのリクエストの一覧を以下に示します。 基本的に、取得、設定どちらでも、ifr_name(デバイス名)は指定しておく必要があります。
リクエスト一覧
リクエスト設定値/戻り値
(struct ifreqのメンバー) |
備考 |
SIOCSIFFLAGS
SIOCGIFFLAGSifr_flags |
デバイスの状態フラグ |
SIOCSIFHWADDR
SIOCGIFHWADDR hwaddr
ifr_hwaddr.sa_family |
ハードウエア情報(MACアドレスなど) |
SIOCSIFADDR
SIOCGIFADDRifr_addr |
アドレス情報(IPアドレスなど) |
SIOCSIFBRDADDR SIOCGIFBRDADDRifr_broadaddr |
ブロードキャストアドレス |
SIOCSIFNETMASK
SIOCGIFNETMASKifr_netmask |
ネットマスク |
使用可能なインターフェイスの取得
全てのデバイスに対してnetDeviceAvailable()関数を実行することで使用可能なインターフェイスの一覧を得ることができます。 しかしデバイスの一覧( eth0, eth1, .., tr0, ppp )を全てソースに記述するのは大変かもしれません。
実は、使用可能なインターフェイスの情報は、/proc/net/dev から参照することが可能です。 試しに、コマンドラインから
cat/proc/net/dev
を実行してみてください。
リスト1のlookupAllInterface()関数では、/proc/net/devから使用可能なデバイス名のリストを取得するようになっています。
IPアドレスの扱い
リスト1の中では、IPアドレスを格納するためのなにやら似たような名前の構造体( struct sockaddr, struct sockaddr_in, struct in_addr)を 見ることができると思います。 sockaddrは、ソケットアドレスの抽象化された型で、sockaddr_inは、 インターネット(ソケット)アドレスの定義になります。sockaddr_in, sockaddr間での型変換は可能です。もう一つのin_addrは、単純にIPv4アドレス(32ビット)を格納するための型だと思ってください。
struct ifreqのメンバーに代入する場合は、struct sockaddr型、 inet_ntoa()関数の場合は、struct in_addr型とか、状況によって変ります。大体のものはmanページで確認できますが、 構造体のメンバーがどの型を使用しているかはヘッダーファイルを見るのが一番でしょう。
もう一つ注意が必要な点は、IPアドレスの計算を行う際です。 inet_aton()関数などが扱うstruct in_addr型の変数は、ネットワークバイトオーダーになっています。 そのためブロードキャストアドレスの計算などマスクを取ったりする処理を直接、 in_addr型の変数に対して行ってしまうとおかしな結果になります。 CPUによってはおかしな結果 にはならないかもしれませんが、良い作法ではないので、 ntohl()関数をを使って計算可能なバイトオーダーにしてから計算してください。 もちろんもとに戻さないと他の処理がおかしくなるのでhtonl()関数も忘れずに。このあたりは、 リスト1のgetIPMask()、configInterface()関数を参考にしてください。
■宿題
今回の紹介した例題プログラムでは、エリアスインターフェイスの処理が実装されていません。 そこでみなさまへの宿題です。このプログラムにエリアスインターフェイスの処理を追加してみてください。 またifconfigコマンドと比較してみて足りない機能を追加して遊んでみてください。ちなみに宿題は、 自己採点にしてくださいね。
おそらく読者の方々は、ifconfigのソースコードを持っていると思いますが、念のために、パッケージ名、URLを書いておきます。 ifconfigのソースコードは
net-toolsに含まれています。
http://www.tazenda.demon.co.uk/phil/net-tools/ からダウンロードで きるでしょう。
なにか分からないことがあったら、気軽にメーリングリスト
dev-intel@turbolinux.co.jpに参加して発言してください。