知恵の実 知恵の実 知恵の実

お手軽!簡単!Linuxでルータを作る

on 2025-09-09

概要

自宅の外向きネットワークを10Gにした
同時に10Gルータの購入を考えたが非常に高額であった為、既存PCを流用しルータを構成することにした

構成環境

スペック

パーツコンポーネント備考
CPUi7-9700K内、4vCPUを割り当て
RAM64GB内、8GBを割り当て
SSDSATA 1TB
NICpci pass-throughでVMに直接マウント
X540-AT2Intel製 2xRJ45
560SFP+HP製 2xSFP+

使用コンポーネント

機能コンポーネント備考
OSUbuntu便利さにはかなわない
DHCPCwide-dhcpv6-clientNGNからのDHCPv6-PD用
SLAACradvdStateless Address Autoconfiguration用
firewallnftablesfirewallとルーティング
DNSunbound

外側ネットワーク

  • en光のxpass契約
  • ipは固定

構築の流れ

OSのインストール

こちらに関しては、基本技能。割愛。

既存のコンポーネントの更新および使用するコンポーネントの入手

  1. # apt update && apt upgrade -y
  2. # apt install -y wide-dhcpv6-client radvd unbound

各種コンポーネントの設定と確認

  • ネットワークインターフェースの割り当て名を確認する
    $ ip a
    v6ネットワークがつながらないと話が始まらないのでDHCPCv6から始める

wide-dhcpv6-client

以下のように編集。説明書はここ
尚、文中のia_idを知りたい場合はリンクを参照

#/etc/wide-dhcpv6/dhcp6c.conf

# Default dhpc6c configuration: it assumes the address is autoconfigured using
# router advertisements.

profile default
{
  information-only;

  request domain-name-servers;
  request domain-name;

  script "/etc/wide-dhcpv6/dhcp6c-script";
};

interface ###PUT YOUR INTERFACE### {
    #このインターフェースでia_pdを送信する。
    #基本的にはここはNTTのONUに接続している端子を設定することになる

        send ia-pd 0;
        #0番としてアドレスブロックの割り当てを要求する
        #ちなみにia_naもあるがこちらはia_Non_temporary_Addressの略
};

id-assoc pd 0{
    #0番で受けたPDに対して対して以下を実行
        prefix-interface ####PUT YOUR INTERFACE ### {
            #受けたIDを指定のinterfaceに割り当て
            #基本的にはこちらは内側LANに接続しているインターフェースになる

                sla-id 1;
                #割り当てを受けたアドレスに対して設定したid 1を付加して再配布させる
                #下の設定と合わせると再配布アドレスが以下のようになる
                #`2001:db8:ffff::/48` -> `2001:db8:ffff:1::/64`

                sla-len 8;
                #今回、SLAACによる自動アドレス設定に対応させるため
                #/64になるように長さを調節する。デフォルトでは/16が設定される
                #NTTからは光電話の契約が無い場合、/56で割り当てを受ける
                #今回は8を設定している
        };
};
#/etc/default/wide-dhcpv6-client

# Defaults for dhcpv6 client initscript
# Used by /etc/init.d/wide-dhcpv6-client

# Interfaces on which the client should send DHCPv6 requests and listen to
# answers. If empty, the client is deactivated.
INTERFACES="####PUT YOUR INTERFACE####"
#ia-pd sendを行う(DHCPCの動きをする)インターフェースを設定する
#基本的にはここはNTTのONUに接続している端子を設定することになる

# Verbose level for syslog. Default is 0 (0: minimal; 1: info; 2: debug)
#VERBOSE=0

radvd

SLAACの設定をする

#/etc/radvd.conf

interface ###LAN側インターフェース {
        AdvOtherConfigFlag on;
        AdvSendAdvert on;
        prefix ::/64 {
        #SLAACは/64で配布する必要がある
                AdvOnLink on;
                AdvAutonomous on;
        };
};

unbound

en光からは、ipipトンネルの接続先情報がドメインとして届いている。接続させるために名前解決できる必要がある
加えて以下の制約がある

  • ipv6での名前解決ができること
#/etc/unbound/unbound.conf

#include-toplevel: "/etc/unbound/unbound.conf.d/*.conf"

server:
        interface: 0.0.0.0
        interface: ::
        interface: ::1

        port: 53
        prefer-ip6: yes
        #適宜 access-controlで名前解決を受けるクライアントの範囲を設定すること

        do-ip4: yes
        do-ip6: yes
        do-udp: yes
        do-tcp: yes

また、名前解決にunboundを使用するように設定を変更する

#/etc/systemd/resolved.conf

[Resolve]
DNS=::1

Unboundと干渉する為、systemd-resolvedを停止する
sudo systemd stop systemd-resolved
sudo systemd disable systemd-resolved

OS設定

この時点でこの設定を行っているマシンを用いてipv6インターネットに出れるはず
ipv4 / ipv6ルーティングはデフォルトでは無効にされているため有効にする
以下のドキュメントを新規作成して、ルーティングを有効にする

# /etc/sysctl.d/10-routing.conf

# Uncomment the next line to enable packet forwarding for IPv4
net.ipv4.ip_forward=1

# Uncomment the next line to enable packet forwarding for IPv6
#  Enabling this option disables Stateless Address Autoconfiguration
#  based on Router Advertisements for this host
net.ipv6.conf.all.forwarding=1

この設定後再起動を行う。
sudo shutdown -r now

nftables

ここでは、firewall, IPマスカレード(NAPT), DNATの設定を行う。
サーバ用途を考えてもいる為、いわゆるポート開放の設定も同時に行う
まずはデフォルト設定を退避させる
cp /etc/nftables.conf /etc/nftables.conf.bak

  • 注意!!一部のフィルタ設定が適切に行われていない可能性がある。この設定は実際の設定ではなく必要な要素のみを抜き出して記載しているため必要な記載がない事がありうる
#/etc/nftables.conf

#!/usr/sbin/nft -f

flush ruleset

define wan_addr = ###YOUR WAN ADDRESS
define wan_if = ###YOUR WAN INTERFACE
#LAN1
define lan1_if = ###YOUR LAN1 INTF
define lan1_addr = ###YOUR LAN1 ADDRESS


table ip f4 {
        chain input {
                type filter hook input priority 0; policy drop;
                ct state established,related counter accept;
                iif $lan1_if accept;
                iif "lo" accept;

                log;
        }

        chain forward {
                type filter hook forward priority 0; policy drop;
                
                tcp flags syn tcp option maxseg size set rt mtu;
                tcp flags rst tcp option maxseg size set rt mtu;
                #Path MTUの自動設定
                #(ip4ip6トンネルはtcp(ipv6パケット)のデータ部分にip4ヘッダが含めて送信する為、defaultの1460だとパケットが分割されてしまいベストな制御ができない)
                #この設定で受信パケットから経路における最大MTU値を自動的に設定するよう構成

                ct state established,related counter accept;
                ip saddr ###lan1_address accept;
                ip saddr ###lan2_address accept;
                ip saddr ###lan3_address accept;

                iif $lan1_if accept;

                iif $wan_if jump if-tun0;
                iif "lo" accept;
                log;

        }

        chain output {
                type filter hook output priority 0; policy accept;
        }

        chain if-tun0{
                tcp dport ###解放するポート accept;

                drop;
        }
}

table ip6 f6 {
        chain input{
                type filter hook input priority 0; policy drop;
                ct state established,related counter accept;
                icmpv6 type {1,2,3,4,128,129,133,134,135,136} accept;
                #ipv6からdhcp関係のパケットはicmpにまとめられたので当該部分を通すように設定

                udp dport 546 ip6 saddr fe80::4e5d:3cff:fe8f:900b accept;
                #ONUのアドレス
                iif $lan1_if accept;
                iif "lo" accept;
        }

        chain forward {
                type filter hook forward priority 0; policy accept;
                
                iif $lan1_if accept;
                iif "lo" accept;
                ct state established,related counter accept;
                icmpv6 type {1,2,3,4,128,129,133,134,135,136} accept;
                #ipv6からDHCP関係の通信がICMPv6にまとめられ為、名前解決関係を通すようにする

                tcp flags syn tcp option maxseg size set rt mtu;
                tcp flags rst tcp option maxseg size set rt mtu;
                #path mtuの設定
                #本来ならいらないがほぼ気休めである
        }

        chain output {
                type filter hook output priority 0; policy accept;
        }

}

table ip nat {
        chain postrouting {
            #NATの設定
            
                type nat hook postrouting priority 0;
                oif "tun0" masquerade;
                #NAPTの設定

                iif $lan1_if ip daddr ###NAT先 tcp dport ###ポート番号 masquerade;
                #ヘアピンNATの設定
        }
        chain prerouting {
                type nat hook prerouting priority 0;
                ip daddr $wan_addr tcp dport ###ポート番号 dnat to ###NAT先;
                #ヘアピンNATの設定
                
                iif "tun0" tcp dport ###ポート番号 dnat to ###NAT先;
        }
}

ISPとトンネルを張る

xpassの固定IP契約はip4ip6トンネルを張ることで利用できるようになる
また、このインターフェースは再起動ごとに設定する必要があるため以下のスクリプトで纏めている

# tunnel.sh

INTERFACE='###トンネルインターフェース'
REMOTE='###ISP側アドレス'
TUNNEL_NAME='###トンネルデバイス名'
ADDRESS4='###割り当て固定IP'
LOCAL=`ip address show $INTERFACE | grep "global" | awk '{print $2}' | awk -F/ '{print $1}'`
#IP6_LOCAL=`ip a show $INTERFACE | grep inet6 | awk '{if(NR==1) print(substr($2,0,length($2)-3)) }'`

#Xpass Local Address Notification Secrets
BASIC_ID='###認証ID'
BASIC_PW='###パスワード'
DDNS_ID='###DDNSエンドポイント'
DDNS_PW='###DDNSのパスワード'

sudo systemctl stop nftables

echo "Create Tunnel Device"
sudo ip -6 tunnel add "$TUNNEL_NAME" mode ip4ip6 remote "$REMOTE" local "$LOCAL" encaplimit none dev "$INTERFACE"

echo "Set Activate Tunnel Device"
sudo ip link set dev "$TUNNEL_NAME" up

sudo ip address add dev "$TUNNEL_NAME" "$ADDRESS4"
sudo ip route delete default
sudo ip route add default dev "$TUNNEL_NAME"

echo "Start Xpass Authentication"
sudo curl --insecure -u $BASIC_ID:$BASIC_PW "https://ddnsweb1.ddns.vbbnet.jp/cgi-bin/ddns_api.cgi?d=4prgyn.v4v6.xpass.jp&p=$DDNS_PW&a=$LOCAL&u=$DDNS_ID"

sudo systemctl start nftables

注意事項

(後学のために)可能な限り設定の説明を含めるようにしているが正確性に関しては読む人自身の自己判断にしたい
また間違えを見つけた場合・解釈が違う場合はGithub上の当ページのリポジトリにissueを残すことで世界から間違いが一つ減る