sai’s diary

プログラミング関連の備忘録とつぶやきを書いています。

IPv6 - 送信元アドレスの選択

ネットワークネタですが、IPv6の場合、単一インタフェースにリンクローカルアドレスやグローバルユニキャストアドレスといった複数のアドレスを設定し、利用することになります。 複数のアドレスを持つ場合、通信時に送信元アドレスを決定する必要がありますが、そのルールを定めているのがRFC3484になります。

RFC3484のルールについて

RFC3484はこちら日本語訳はこちらになります。(翻訳してくださったIshida Soさんに感謝)

RFC3484の5章を参照すると8つのルールが優先度順に書かれています。

Rule 1:  Prefer same address.
If SA = D, then prefer SA.  Similarly, if SB = D, then prefer SB.
規則1:同じアドレスが優先。
もしSA=Dなら、SAが優先で、同様にSB=DならSBが優先です。

Rule 2:  Prefer appropriate scope.
If Scope(SA) < Scope(SB): If Scope(SA) < Scope(D), then prefer SB
and otherwise prefer SA.  Similarly, if Scope(SB) < Scope(SA): If
Scope(SB) < Scope(D), then prefer SA and otherwise prefer SB.
規則2:適切範囲が優先。
もしScope(SA)<Scope(SB)なら:もしScope(SA)<Scope(D)なら、SBが優先
で、そうでなければSAが優先です。同様に、もし範囲Scope(SB)<Scope(SA)
なら:もしScope(SB)<Scope(D)なら、SAが優先で、さもなければSBが優
先です。

Rule 3:  Avoid deprecated addresses.
The addresses SA and SB have the same scope.  If one of the two
source addresses is "preferred" and one of them is "deprecated" (in
the RFC 2462 sense), then prefer the one that is "preferred."
規則3:抑制アドレスを避ける。
アドレスSAとSBは同じ範囲です。(RFC2462の意味で)もし2つ
のソースアドレスのうち1つが「好ましい」くもう1つが「抑制」なら、
「好ましい」方が優先です。

Rule 4:  Prefer home addresses.
If SA is simultaneously a home address and care-of address and SB is
not, then prefer SA.  Similarly, if SB is simultaneously a home
address and care-of address and SA is not, then prefer SB.
If SA is just a home address and SB is just a care-of address, then
prefer SA.  Similarly, if SB is just a home address and SA is just a
care-of address, then prefer SB.
規則4:ホームアドレスが優先。
もしSAがホームアドレス兼立ち寄りアドレスで、SBがそうではないなら、
SAが優先です。同様に、もしSBがホームアドレス兼立ち寄りアドレスで、
SAがそうではないなら、SBが優先です。もしSAがホームアドレスで、
SBが立ち寄りアドレスであるなら、SAが優先です。同様に、もしSBが
ホームアドレスで、SAが立ち寄りアドレスであるなら、SBが優先です。

Implementations should provide a mechanism allowing an application to
reverse the sense of this preference and prefer care-of addresses
over home addresses (e.g., via appropriate API extensions).  Use of
the mechanism should only affect the selection rules for the invoking
application.
アプリケーションがこの優先性の意味を反転し、ホームアドレスより立ち寄
りアドレスを優先とするのを可能するメカニズム(例えば、適切なAPI拡
張)を、実装が供給するべきです。メカニズムを使用する事がただそのアプ
リケーションの選択規則に影響を与えるだけであるべきです。

Rule 5:  Prefer outgoing interface.
If SA is assigned to the interface that will be used to send to D
and SB is assigned to a different interface, then prefer SA.
Similarly, if SB is assigned to the interface that will be used to
send to D and SA is assigned to a different interface, then prefer
SB.
規則5:外向インタフェースが優先。
もしSAがDに送信するために使われるインタフェースに割り当てられ、S
Bが異なるインタフェースに割り当てられるなら、SAが優先です。同様に、
もしSBがDに送信するために使われるインタフェースに割り当てられ、S
Aが異なるインタフェースに割り当てられるなら、SBが優先です。

Rule 6:  Prefer matching label.
If Label(SA) = Label(D) and Label(SB) <> Label(D), then prefer SA.
Similarly, if Label(SB) = Label(D) and Label(SA) <> Label(D), then
prefer SB.
規則6:ラベルの一致が優先。
もしLabel(SA)=Label(D)かつLabel(SB)≠Label(D)ならSAが優先です。同
様に、もしLabel(SB)=Label(D)かつLabel(SA)≠Label(D)ならSAが優先で
す。

Rule 7:  Prefer public addresses.
If SA is a public address and SB is a temporary address, then prefer
SA.  Similarly, if SB is a public address and SA is a temporary
address, then prefer SB.
規則7:公共アドレスが優先。
もしSAが公共アドレスで、SBが一時的なアドレスであるなら、SAが優
先です。同様に、もしSBが公共アドレスで、SAが一時的なアドレスであ
るなら、SBが優先です。

Implementations MUST provide a mechanism allowing an application to
reverse the sense of this preference and prefer temporary addresses
over public addresses (e.g., via appropriate API extensions).  Use of
the mechanism should only affect the selection rules for the invoking
application. This rule avoids applications potentially failing due to
the relatively short lifetime of temporary addresses or due to the
possibility of the reverse lookup of a temporary address either
failing or returning a randomized name.  Implementations for which
privacy considerations outweigh these application compatibility
concerns MAY reverse the sense of this rule and by default prefer
temporary addresses over public addresses.
アプリケーションがこの優先性の意味を反転し、公共アドレスより一時的ア
ドレスを優先する事を可能にするメカニズム(例えば、適切な API拡張
で)を、実装が供給しなくてはなりません(MUST)。メカニズムの使用がただ
そのアプリケーションの選択規則に影響を与えるだけであるべきです。この
規則は一時的アドレスの比較的短い寿命による失敗や、一時的なアドレスの
逆検索が失敗するかランダムな名前を返す可能性による、潜在的なアプリケー
ションの失敗を避けます。アプリケーション互換性懸念よりもプライバシー
の考慮が重要な実装が、この規則の意味を反転し、デフォルトで公共アドレ
スより一時的アドレスを優先するかもしれません(MAY)。

Rule 8:  Use longest matching prefix.
If CommonPrefixLen(SA, D) > CommonPrefixLen(SB, D), then prefer SA.
Similarly, if CommonPrefixLen(SB, D) > CommonPrefixLen(SA, D), then
prefer SB.
規則8:最長一致プレフィックスの使用。
もしCommonPrefixLen(SA, D) > CommonPrefixLen(SB, D)なら、SAが優先で
す。同様に、もしCommonPrefixLen(SB, D) > CommonPrefixLen(SA, D)なら、
SBが優先です。

Rule 8 may be superseded if the implementation has other means of
choosing among source addresses.  For example, if the implementation
somehow knows which source address will result in the "best"
communications performance.
規則8は、もし実装がソースアドレス選択の他の手段を持っているなら、置
き換えられるかもしれません。例えば、もし実装がどのソースアドレスが
「最も良い」通信性能をもたらすか知っているなら、です。

Rule 2 (prefer appropriate scope) MUST be implemented and given high
priority because it can affect interoperability.
規則2が(適切な範囲が優先)は相互運用性に影響を与えるから、実装され、
高い優先権を与えられなくてはなりません(MUST)。

ルール3の利用

例えば、IPv6アドレスを設定する際にわざとpreferred_lft=0で設定することで対象のアドレスが送信元アドレスに選択されない様にすることが可能です。 preferred_lft=0に設定したアドレスはプログラムでbind()を利用すれば送信元アドレスとして利用することが可能です。

[user@localhost ~]$ sudo ip -6 addr add dev eth0 fd97:a134:d707::1/48 preferred_lft 0
[user@localhost ~]$ ip -6 addr show dev eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qlen 1000
    inet6 fd97:a134:d707::1/48 scope global deprecated
       valid_lft forever preferred_lft forever
    inet6 fe80::a00:27ff:fe58:827e/64 scope link
       valid_lft forever preferred_lft forever

ルール6の利用

ルール6を利用すればプログラムの修正を行わずに送信元アドレスを変更できます。 Linuxではip addrlabelコマンドが用意されており、ユーザ独自のルールを追加することが可能です。 ip addrlabelコマンドを利用する場合はプログラムの修正は不要になります。

Linuxの実装について

動作確認をしているCentOS6.5(Linux2.6.32)に近いバージョンのソースをLXRで見てみると以下に送信元アドレス選択のロジックがありました。 ソースコードを見ると上記のルール1~8以外にルール0としてテンタティブアドレス(DADチェック中のアドレス?)の使用も抑止されていることが解ります。

送信元アドレス選択ロジック

920 int ipv6_dev_get_saddr(struct net_device *daddr_dev,
921                        struct in6_addr *daddr, struct in6_addr *saddr)
922 {
923         struct ipv6_saddr_score hiscore;
924         struct inet6_ifaddr *ifa_result = NULL;
925         int daddr_type = __ipv6_addr_type(daddr);
926         int daddr_scope = __ipv6_addr_src_scope(daddr_type);
927         int daddr_ifindex = daddr_dev ? daddr_dev->ifindex : 0;
928         u32 daddr_label = ipv6_addr_label(daddr, daddr_type, daddr_ifindex);
929         struct net_device *dev;
930 
931         memset(&hiscore, 0, sizeof(hiscore));
932 
933         read_lock(&dev_base_lock);
934         rcu_read_lock();
935 
936         for_each_netdev(&init_net, dev) {
937                 struct inet6_dev *idev;
938                 struct inet6_ifaddr *ifa;
939 
940                 /* Rule 0: Candidate Source Address (section 4)
941                  *  - multicast and link-local destination address,
942                  *    the set of candidate source address MUST only
943                  *    include addresses assigned to interfaces
944                  *    belonging to the same link as the outgoing
945                  *    interface.
946                  * (- For site-local destination addresses, the
947                  *    set of candidate source addresses MUST only
948                  *    include addresses assigned to interfaces
949                  *    belonging to the same site as the outgoing
950                  *    interface.)
951                  */
952                 if ((daddr_type & IPV6_ADDR_MULTICAST ||
953                      daddr_scope <= IPV6_ADDR_SCOPE_LINKLOCAL) &&
954                     daddr_dev && dev != daddr_dev)
955                         continue;
956 
957                 idev = __in6_dev_get(dev);
958                 if (!idev)
959                         continue;
960 
961                 read_lock_bh(&idev->lock);
962                 for (ifa = idev->addr_list; ifa; ifa = ifa->if_next) {
963                         struct ipv6_saddr_score score;
964 
965                         score.addr_type = __ipv6_addr_type(&ifa->addr);
966 
967                         /* Rule 0:
968                          * - Tentative Address (RFC2462 section 5.4)
969                          *  - A tentative address is not considered
970                          *    "assigned to an interface" in the traditional
971                          *    sense, unless it is also flagged as optimistic.
972                          * - Candidate Source Address (section 4)
973                          *  - In any case, anycast addresses, multicast
974                          *    addresses, and the unspecified address MUST
975                          *    NOT be included in a candidate set.
976                          */
977                         if ((ifa->flags & IFA_F_TENTATIVE) &&
978                             (!(ifa->flags & IFA_F_OPTIMISTIC)))
979                                 continue;
980                         if (unlikely(score.addr_type == IPV6_ADDR_ANY ||
981                                      score.addr_type & IPV6_ADDR_MULTICAST)) {
982                                 LIMIT_NETDEBUG(KERN_DEBUG
983                                                "ADDRCONF: unspecified / multicast address "
984                                                "assigned as unicast address on %s",
985                                                dev->name);
986                                 continue;
987                         }
988 
989                         score.attrs = 0;
990                         score.matchlen = 0;
991                         score.scope = 0;
992                         score.rule = 0;
993 
994                         if (ifa_result == NULL) {
995                                 /* record it if the first available entry */
996                                 goto record_it;
997                         }
998 
999                         /* Rule 1: Prefer same address */
1000                         if (hiscore.rule < 1) {
1001                                 if (ipv6_addr_equal(&ifa_result->addr, daddr))
1002                                         hiscore.attrs |= IPV6_SADDR_SCORE_LOCAL;
1003                                 hiscore.rule++;
1004                         }
1005                         if (ipv6_addr_equal(&ifa->addr, daddr)) {
1006                                 score.attrs |= IPV6_SADDR_SCORE_LOCAL;
1007                                 if (!(hiscore.attrs & IPV6_SADDR_SCORE_LOCAL)) {
1008                                         score.rule = 1;
1009                                         goto record_it;
1010                                 }
1011                         } else {
1012                                 if (hiscore.attrs & IPV6_SADDR_SCORE_LOCAL)
1013                                         continue;
1014                         }
1015 
1016                         /* Rule 2: Prefer appropriate scope */
1017                         if (hiscore.rule < 2) {
1018                                 hiscore.scope = __ipv6_addr_src_scope(hiscore.addr_type);
1019                                 hiscore.rule++;
1020                         }
1021                         score.scope = __ipv6_addr_src_scope(score.addr_type);
1022                         if (hiscore.scope < score.scope) {
1023                                 if (hiscore.scope < daddr_scope) {
1024                                         score.rule = 2;
1025                                         goto record_it;
1026                                 } else
1027                                         continue;
1028                         } else if (score.scope < hiscore.scope) {
1029                                 if (score.scope < daddr_scope)
1030                                         break; /* addresses sorted by scope */
1031                                 else {
1032                                         score.rule = 2;
1033                                         goto record_it;
1034                                 }
1035                         }
1036 
1037                         /* Rule 3: Avoid deprecated and optimistic addresses */
1038                         if (hiscore.rule < 3) {
1039                                 if (ipv6_saddr_preferred(hiscore.addr_type) ||
1040                                    (((ifa_result->flags &
1041                                     (IFA_F_DEPRECATED|IFA_F_OPTIMISTIC)) == 0)))
1042                                         hiscore.attrs |= IPV6_SADDR_SCORE_PREFERRED;
1043                                 hiscore.rule++;
1044                         }
1045                         if (ipv6_saddr_preferred(score.addr_type) ||
1046                            (((ifa->flags &
1047                             (IFA_F_DEPRECATED|IFA_F_OPTIMISTIC)) == 0))) {
1048                                 score.attrs |= IPV6_SADDR_SCORE_PREFERRED;
1049                                 if (!(hiscore.attrs & IPV6_SADDR_SCORE_PREFERRED)) {
1050                                         score.rule = 3;
1051                                         goto record_it;
1052                                 }
1053                         } else {
1054                                 if (hiscore.attrs & IPV6_SADDR_SCORE_PREFERRED)
1055                                         continue;
1056                         }
1057 
1058                         /* Rule 4: Prefer home address */
1059 #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
1060                         if (hiscore.rule < 4) {
1061                                 if (ifa_result->flags & IFA_F_HOMEADDRESS)
1062                                         hiscore.attrs |= IPV6_SADDR_SCORE_HOA;
1063                                 hiscore.rule++;
1064                         }
1065                         if (ifa->flags & IFA_F_HOMEADDRESS) {
1066                                 score.attrs |= IPV6_SADDR_SCORE_HOA;
1067                                 if (!(ifa_result->flags & IFA_F_HOMEADDRESS)) {
1068                                         score.rule = 4;
1069                                         goto record_it;
1070                                 }
1071                         } else {
1072                                 if (hiscore.attrs & IPV6_SADDR_SCORE_HOA)
1073                                         continue;
1074                         }
1075 #else
1076                         if (hiscore.rule < 4)
1077                                 hiscore.rule++;
1078 #endif
1079 
1080                         /* Rule 5: Prefer outgoing interface */
1081                         if (hiscore.rule < 5) {
1082                                 if (daddr_dev == NULL ||
1083                                     daddr_dev == ifa_result->idev->dev)
1084                                         hiscore.attrs |= IPV6_SADDR_SCORE_OIF;
1085                                 hiscore.rule++;
1086                         }
1087                         if (daddr_dev == NULL ||
1088                             daddr_dev == ifa->idev->dev) {
1089                                 score.attrs |= IPV6_SADDR_SCORE_OIF;
1090                                 if (!(hiscore.attrs & IPV6_SADDR_SCORE_OIF)) {
1091                                         score.rule = 5;
1092                                         goto record_it;
1093                                 }
1094                         } else {
1095                                 if (hiscore.attrs & IPV6_SADDR_SCORE_OIF)
1096                                         continue;
1097                         }
1098 
1099                         /* Rule 6: Prefer matching label */
1100                         if (hiscore.rule < 6) {
1101                                 if (ipv6_addr_label(&ifa_result->addr,
1102                                                     hiscore.addr_type,
1103                                                     ifa_result->idev->dev->ifindex) == daddr_label)
1104                                         hiscore.attrs |= IPV6_SADDR_SCORE_LABEL;
1105                                 hiscore.rule++;
1106                         }
1107                         if (ipv6_addr_label(&ifa->addr,
1108                                             score.addr_type,
1109                                             ifa->idev->dev->ifindex) == daddr_label) {
1110                                 score.attrs |= IPV6_SADDR_SCORE_LABEL;
1111                                 if (!(hiscore.attrs & IPV6_SADDR_SCORE_LABEL)) {
1112                                         score.rule = 6;
1113                                         goto record_it;
1114                                 }
1115                         } else {
1116                                 if (hiscore.attrs & IPV6_SADDR_SCORE_LABEL)
1117                                         continue;
1118                         }
1119 
1120 #ifdef CONFIG_IPV6_PRIVACY
1121                         /* Rule 7: Prefer public address
1122                          * Note: prefer temprary address if use_tempaddr >= 2
1123                          */
1124                         if (hiscore.rule < 7) {
1125                                 if ((!(ifa_result->flags & IFA_F_TEMPORARY)) ^
1126                                     (ifa_result->idev->cnf.use_tempaddr >= 2))
1127                                         hiscore.attrs |= IPV6_SADDR_SCORE_PRIVACY;
1128                                 hiscore.rule++;
1129                         }
1130                         if ((!(ifa->flags & IFA_F_TEMPORARY)) ^
1131                             (ifa->idev->cnf.use_tempaddr >= 2)) {
1132                                 score.attrs |= IPV6_SADDR_SCORE_PRIVACY;
1133                                 if (!(hiscore.attrs & IPV6_SADDR_SCORE_PRIVACY)) {
1134                                         score.rule = 7;
1135                                         goto record_it;
1136                                 }
1137                         } else {
1138                                 if (hiscore.attrs & IPV6_SADDR_SCORE_PRIVACY)
1139                                         continue;
1140                         }
1141 #else
1142                         if (hiscore.rule < 7)
1143                                 hiscore.rule++;
1144 #endif
1145                         /* Rule 8: Use longest matching prefix */
1146                         if (hiscore.rule < 8) {
1147                                 hiscore.matchlen = ipv6_addr_diff(&ifa_result->addr, daddr);
1148                                 hiscore.rule++;
1149                         }
1150                         score.matchlen = ipv6_addr_diff(&ifa->addr, daddr);
1151                         if (score.matchlen > hiscore.matchlen) {
1152                                 score.rule = 8;
1153                                 goto record_it;
1154                         }
1155 #if 0
1156                         else if (score.matchlen < hiscore.matchlen)
1157                                 continue;
1158 #endif
1159 
1160                         /* Final Rule: choose first available one */
1161                         continue;
1162 record_it:
1163                         if (ifa_result)
1164                                 in6_ifa_put(ifa_result);
1165                         in6_ifa_hold(ifa);
1166                         ifa_result = ifa;
1167                         hiscore = score;
1168                 }
1169                 read_unlock_bh(&idev->lock);
1170         }
1171         rcu_read_unlock();
1172         read_unlock(&dev_base_lock);
1173 
1174         if (!ifa_result)
1175                 return -EADDRNOTAVAIL;
1176 
1177         ipv6_addr_copy(saddr, &ifa_result->addr);
1178         in6_ifa_put(ifa_result);
1179         return 0;
1180 }

スコープの決定ロジック

 26 int __ipv6_addr_type(const struct in6_addr *addr)
 27 {
 28         __be32 st;
 29 
 30         st = addr->s6_addr32[0];
 31 
 32         /* Consider all addresses with the first three bits different of
 33            000 and 111 as unicasts.
 34          */
 35         if ((st & htonl(0xE0000000)) != htonl(0x00000000) &&
 36             (st & htonl(0xE0000000)) != htonl(0xE0000000))
 37                 return (IPV6_ADDR_UNICAST |
 38                         IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));
 39 
 40         if ((st & htonl(0xFF000000)) == htonl(0xFF000000)) {
 41                 /* multicast */
 42                 /* addr-select 3.1 */
 43                 return (IPV6_ADDR_MULTICAST |
 44                         ipv6_addr_scope2type(IPV6_ADDR_MC_SCOPE(addr)));
 45         }
 46 
 47         if ((st & htonl(0xFFC00000)) == htonl(0xFE800000))
 48                 return (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_UNICAST |
 49                         IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL));               /* addr-select 3.1 */
 50         if ((st & htonl(0xFFC00000)) == htonl(0xFEC00000))
 51                 return (IPV6_ADDR_SITELOCAL | IPV6_ADDR_UNICAST |
 52                         IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_SITELOCAL));               /* addr-select 3.1 */
 53         if ((st & htonl(0xFE000000)) == htonl(0xFC000000))
 54                 return (IPV6_ADDR_UNICAST |
 55                         IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));                  /* RFC 4193 */
 56 
 57         if ((addr->s6_addr32[0] | addr->s6_addr32[1]) == 0) {
 58                 if (addr->s6_addr32[2] == 0) {
 59                         if (addr->s6_addr32[3] == 0)
 60                                 return IPV6_ADDR_ANY;
 61 
 62                         if (addr->s6_addr32[3] == htonl(0x00000001))
 63                                 return (IPV6_ADDR_LOOPBACK | IPV6_ADDR_UNICAST |
 64                                         IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL));       /* addr-select 3.4 */
 65 
 66                         return (IPV6_ADDR_COMPATv4 | IPV6_ADDR_UNICAST |
 67                                 IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));  /* addr-select 3.3 */
 68                 }
 69 
 70                 if (addr->s6_addr32[2] == htonl(0x0000ffff))
 71                         return (IPV6_ADDR_MAPPED |
 72                                 IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));  /* addr-select 3.3 */
 73         }
 74 
 75         return (IPV6_ADDR_RESERVED |
 76                 IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));  /* addr-select 3.4 */
 77 }