在Linux中传出流量的IPv6源地址选择的上下文中:
我在接口上有一些IPv6地址。 我希望内核选择其中一个作为源IPv6地址。 我不希望内核选择这个地址,我将把它作为传出数据包的源地址发送。
更具体地说,在此片段中,当dontUseAsSourceAddressForOutgoingPkts为true时,我希望内核选择此接口上已有的任何其他IPv6地址。 什么标志会产生这种效果? 如果我使用错误的ifaddrmsg结构进行IPv6寻址,我应该使用哪一个?
包含更多上下文的片段:
int
NetLnkSock::IpAdd(const std::string &ifname,
const IpAddr &ipaddr,
int prefixlen,
bool dontUseAsSourceAddressForOutgoingPkts)
ifreq ifr;
nlmsghdr *nlh;
ifaddrmsg *ifa;
nlmsgerr *nlerr;
static uint32_t msg_seq = 0;
NlSock nlsock;
LogDev::Ostream logostr;
nlsock.bind();
memset(&ifr, 0, sizeof(ifr));
if (ifname.size() > IFNAMSIZ)
throw NetLnkNameErr();
copy(ifname.begin(), ifname.end(), ifr.ifr_name);
ifr.ifr_name[ifname.end() - ifname.begin()] = '\0';
nlh = (nlmsghdr *)rcvbuf;
nlh->nlmsg_len = sizeof(nlmsghdr);
nlh->nlmsg_type = RTM_NEWADDR;
nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
nlh->nlmsg_seq = ++msg_seq;
nlh->nlmsg_pid = 0;
ifa = (ifaddrmsg *)&nlh[1];
ifa->ifa_family = (ipaddr.is_v4()) ? AF_INET : AF_INET6;
ifa->ifa_prefixlen = prefixlen;
/*
* My question is about the behavior of the kernel
* vis a vis source address selection for outgoing traffic
* where there are multiple IP's on this interface.
* How do the flags below impact the kernel's choice
* for source address selection?
*/
ifa->ifa_flags =
(dontUseAsSourceAddressForOutgoingPkts && ipaddr.is_v6()) ?
(IFA_F_SECONDARY | IFA_F_DEPRECATED) : 0;
/*
* I would like for the kernel to select any other IPv6
* address already on this interface when
* dontUseAsSourceAddressForOutgoingPkts is true.
* Will these flags yield that effect?
*/
ifa->ifa_scope = RT_SCOPE_UNIVERSE;
ifa->ifa_index = ifr.ifr_ifindex;
nlh->nlmsg_len += sizeof(ifaddrmsg);
if (ipaddr.is_v4()) {
IpAddr ip4_bcast;
char *buf = rcvbuf + nlh->nlmsg_len;
ip4_bcast.create_netmask(prefixlen, ipaddr);
ip4_bcast.from_v4(~ip4_bcast.get_v4() | ipaddr.get_v4());
nlh->nlmsg_len += NLMSG_ALIGN(setRtAttr(buf, IFA_LOCAL,
&ipaddr.get_v4(), sizeof(in_addr_t)));
/*
* Always send the netmask and broadcast even on delete.
* Linux seems to ignore the prefixlen set in the original
* message and simply matches by ip address on deletes.
*/
buf = rcvbuf + nlh->nlmsg_len;
nlh->nlmsg_len += NLMSG_ALIGN(setRtAttr(buf, IFA_ADDRESS,
&ipaddr.get_v4(), sizeof(in_addr_t)));
buf = rcvbuf + nlh->nlmsg_len;
nlh->nlmsg_len += NLMSG_ALIGN(setRtAttr(buf, IFA_BROADCAST,
&ip4_bcast.get_v4(), sizeof(in_addr_t)));
} else { /* AF_INET6 */
char *buf = rcvbuf + nlh->nlmsg_len;
buf = rcvbuf + nlh->nlmsg_len;
if (ipaddr.domain() != RD_DEFAULT_ID) { // Hal doesn't support route domains
throw NetLnkIpAddrErr();
}
nlh->nlmsg_len += NLMSG_ALIGN(setRtAttr(buf, IFA_LOCAL,
&ipaddr.get_v6(), sizeof(in6_addr)));
buf = rcvbuf + nlh->nlmsg_len;
nlh->nlmsg_len += NLMSG_ALIGN(setRtAttr(buf, IFA_ADDRESS,
&ipaddr.get_v6(), sizeof(in6_addr)));
}
nlsock.sendNlReq(rcvbuf);
}
答案 0 :(得分:1)
RFC 3484州:
源地址选择
< ...>
规则3:避免弃用地址。 地址SA和SB具有相同的范围。如果是其中之一 源地址是“首选”,其中一个是“已弃用”(in RFC 2462感觉),然后更喜欢那个“首选”。
< ...>
rtnetlink(7) man pages简要提到了一个名为ifa_cacheinfo的结构。
This struct包含两个值得注意的导入标志:ifa_valid和ifa_prefered。 为了将IPv6地址标记为已弃用,请将其prefered_lft设置为零。此外,似乎还习惯将valid_lft设置为0xffffffff(永远)以强调此IPv6地址明确弃用的性质。
/*
* You have just put a new IPv6 address on the kernel with
* net link. You don't want it chosen as the source address
* of packets leaving this interface if there's at least one
* other IPv6 address already on this interface.
*
* Mark this IPv6 address as Deprecated on this interface,
* Causing LINUX not to choose it for source address of
* packets outgoing from this interface when there exists
* another, non-deprecated IPv6 address on this interface
*/
struct ifa_cacheinfo ci;
// This address is valid forever
ci.ifa_valid = 0xffffffff;
// A prefered ttl of 0 immediately deprecates this IPv6
ci.ifa_preferred = 0;
// <Send this cacheinfo to the kernel using net link>
答案 1 :(得分:0)
ifa_flags
是辅助地址(旧别名接口)IFA_F_SECONDARY
的标志字,IFA_F_PERMANENT
是用户设置的永久地址和其他未记录的标记。
确实,the kernel sources似乎没有记录它们:
/* ifa_flags */
#define IFA_F_SECONDARY 0x01
#define IFA_F_TEMPORARY IFA_F_SECONDARY
#define IFA_F_NODAD 0x02
#define IFA_F_OPTIMISTIC 0x04
#define IFA_F_DADFAILED 0x08
#define IFA_F_HOMEADDRESS 0x10
#define IFA_F_DEPRECATED 0x20
#define IFA_F_TENTATIVE 0x40
#define IFA_F_PERMANENT 0x80
#define IFA_F_MANAGETEMPADDR 0x100
#define IFA_F_NOPREFIXROUTE 0x200
#define IFA_F_MCAUTOJOIN 0x400
#define IFA_F_STABLE_PRIVACY 0x800
然而,RFC 3549 "Linux Netlink as an IP Services Protocol"澄清了一点:
Flags: 8 bits
IFA_F_SECONDARY For secondary address (alias interface).
IFA_F_PERMANENT For a permanent address set by the user.
When this is not set, it means the address
was dynamically created (e.g., by stateless
autoconfiguration).
IFA_F_DEPRECATED Defines deprecated (IPV4) address.
IFA_F_TENTATIVE Defines tentative (IPV4) address (duplicate
address detection is still in progress).
所以似乎两个标志没有关联:一个标记接口地址为辅助(临时);而另一个定义了IPv4地址(&#34;弃用&#34;)。
如果您需要确切了解每个标志的含义,可以查看源代码中符号的引用,例如IFA_F_SECONDARY
和IFA_F_DEPRECATED
。