C 言語を用いたネットワーク MTU 値の動的取得方法

POSIX準拠の環境において、C プログラムからネットワークインターフェースの最大伝送単位(MTU)情報を取得する一般的なアプローチについて記述します。このプロセスには、ソケットの作成と、ioctl関数を介したデバイス制御が必要です。

対象インターフェースの特定

まずは現在アクティブなネットワークアダプタを確認します。ターミナルで以下コマンドを実行し、使用されているインターフェース名を把握してください。

$ ifconfig
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
...
en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
	ether a4:5e:60:d6:57:17
	inet 192.168.16.103 netmask 0xffffff00 broadcast 192.168.16.255
...

上記の出力例では en0 が有効な IP アドレスを持ち、通信に使用されていることがわかります。Linux システムでは通常 eth0 や wlan0 などが採用される傾向にあります。

実装コード

以下のソースコードは、指定されたインターフェース名の MTU を取得する最小限の実装です。SIOCGIFMTU リクエストを使用して設定値を取得します。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>
#include <errno.h>

#define DEFAULT_IFACE "eth0"

int main(int argc, char *argv[]) {
    const char *iface_name;
    int sock_fd;
    struct ifreq request_info;

    // インターフェース名引数の指定がある場合は優先
    iface_name = argv[1] ? argv[1] : DEFAULT_IFACE;

    // データグラムソケットの生成(IP プロトコルなし)
    sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock_fd < 0) {
        perror("socket");
        return EXIT_FAILURE;
    }

    // インターフェース名のセット
    strncpy(request_info.ifr_name, iface_name, sizeof(request_info.ifr_name) - 1);
    request_info.ifr_name[sizeof(request_info.ifr_name) - 1] = '\0';

    // MTU 情報の取得リクエスト
    if (ioctl(sock_fd, SIOCGIFMTU, &request_info) != 0) {
        perror("ioctl: 情報取得エラー");
        close(sock_fd);
        return EXIT_FAILURE;
    }

    close(sock_fd);
    
    // 結果の出力
    printf("%s の MTU は %d です\n", iface_name, request_info.ifr_mtu);

    return EXIT_SUCCESS;
}

ビルドおよび実行

GCC を使用してコンパイルし、実行すると現在のインターフェース設定が確認できます。

$ gcc -o mtu_check mtu_check.c
$ ./mtu_check
en0 の MTU は 1500 です

正常終了時の出力値は、該当環境でのフレームサイズ制限を示しています。

内部仕様と構造体

本機能を実現するために使用する主要な構造体と定数は以下の通りです。

  • socket(): AF_INET ドメインのデータグラムソケットを作成します。プロトコルは 0(デフォルト)とするのが一般的です。
  • struct ifreq: インターフェース情報を格納します。ここでは名前を含む文字列配列と、union 部分に含まれる ifr_mtu フィールドを利用します。
  • SIOCGIFMTU: グローバル変数ではなく、システムヘッダ定義されるリクエストコードです。これによりカーネルへ問い合わせを行います。
  • ioctl(): デバイス制御のための汎用システムコールで、第一引数にソケットファイルディスクリプタ、第二引数にリクエストコード、第三引数に構造体のポインタを渡します。

これらの API を適切に組み合わせることで、アプリケーション側で動的にネットワーク設定を読み取ることができます。

タグ: C 言語,POSIX,ネットワーク制御,ioctl,sys/socket.h

10月10日 19:56 投稿