1 /* NHRP netlink/neighbor table arpd code
2 * Copyright (c) 2014-2016 Timo Teräs
4 * This file is free software: you may copy, redistribute and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
12 #include <netinet/if_ether.h>
13 #include <linux/netlink.h>
14 #include <linux/neighbour.h>
15 #include <linux/netfilter/nfnetlink_log.h>
22 int netlink_req_fd
= -1;
23 int netlink_nflog_group
;
24 static int netlink_log_fd
= -1;
25 static struct thread
*netlink_log_thread
;
26 static int netlink_listen_fd
= -1;
28 typedef void (*netlink_dispatch_f
)(struct nlmsghdr
*msg
, struct zbuf
*zb
);
30 void netlink_update_binding(struct interface
*ifp
, union sockunion
*proto
,
31 union sockunion
*nbma
)
35 struct zbuf
*zb
= zbuf_alloc(512);
37 n
= znl_nlmsg_push(zb
, nbma
? RTM_NEWNEIGH
: RTM_DELNEIGH
,
38 NLM_F_REQUEST
| NLM_F_REPLACE
| NLM_F_CREATE
);
39 ndm
= znl_push(zb
, sizeof(*ndm
));
40 *ndm
= (struct ndmsg
){
41 .ndm_family
= sockunion_family(proto
),
42 .ndm_ifindex
= ifp
->ifindex
,
43 .ndm_type
= RTN_UNICAST
,
44 .ndm_state
= nbma
? NUD_REACHABLE
: NUD_FAILED
,
46 znl_rta_push(zb
, NDA_DST
, sockunion_get_addr(proto
),
47 family2addrsize(sockunion_family(proto
)));
49 znl_rta_push(zb
, NDA_LLADDR
, sockunion_get_addr(nbma
),
50 family2addrsize(sockunion_family(nbma
)));
51 znl_nlmsg_complete(zb
, n
);
52 zbuf_send(zb
, netlink_req_fd
);
53 zbuf_recv(zb
, netlink_req_fd
);
57 static void netlink_neigh_msg(struct nlmsghdr
*msg
, struct zbuf
*zb
)
62 struct interface
*ifp
;
66 char buf
[SU_ADDRSTRLEN
];
69 ndm
= znl_pull(zb
, sizeof(*ndm
));
73 sockunion_family(&addr
) = AF_UNSPEC
;
74 while ((rta
= znl_rta_pull(zb
, &payload
)) != NULL
) {
75 len
= zbuf_used(&payload
);
76 switch (rta
->rta_type
) {
78 sockunion_set(&addr
, ndm
->ndm_family
,
79 zbuf_pulln(&payload
, len
), len
);
84 ifp
= if_lookup_by_index(ndm
->ndm_ifindex
, VRF_DEFAULT
);
85 if (!ifp
|| sockunion_family(&addr
) == AF_UNSPEC
)
88 c
= nhrp_cache_get(ifp
, &addr
, 0);
92 if (msg
->nlmsg_type
== RTM_GETNEIGH
) {
93 debugf(NHRP_DEBUG_KERNEL
, "Netlink: who-has %s dev %s",
94 sockunion2str(&addr
, buf
, sizeof buf
), ifp
->name
);
96 if (c
->cur
.type
>= NHRP_CACHE_CACHED
) {
97 nhrp_cache_set_used(c
, 1);
98 netlink_update_binding(ifp
, &addr
,
99 &c
->cur
.peer
->vc
->remote
.nbma
);
102 debugf(NHRP_DEBUG_KERNEL
, "Netlink: update %s dev %s nud %x",
103 sockunion2str(&addr
, buf
, sizeof buf
), ifp
->name
,
106 state
= (msg
->nlmsg_type
== RTM_NEWNEIGH
) ? ndm
->ndm_state
108 nhrp_cache_set_used(c
, state
== NUD_REACHABLE
);
112 static int netlink_route_recv(struct thread
*t
)
114 uint8_t buf
[ZNL_BUFFER_SIZE
];
115 int fd
= THREAD_FD(t
);
116 struct zbuf payload
, zb
;
119 zbuf_init(&zb
, buf
, sizeof(buf
), 0);
120 while (zbuf_recv(&zb
, fd
) > 0) {
121 while ((n
= znl_nlmsg_pull(&zb
, &payload
)) != 0) {
122 debugf(NHRP_DEBUG_KERNEL
,
123 "Netlink: Received msg_type %u, msg_flags %u",
124 n
->nlmsg_type
, n
->nlmsg_flags
);
125 switch (n
->nlmsg_type
) {
129 netlink_neigh_msg(n
, &payload
);
135 thread_add_read(master
, netlink_route_recv
, 0, fd
, NULL
);
140 static void netlink_log_register(int fd
, int group
)
144 struct nfulnl_msg_config_cmd cmd
;
145 struct zbuf
*zb
= zbuf_alloc(512);
147 n
= znl_nlmsg_push(zb
, (NFNL_SUBSYS_ULOG
<< 8) | NFULNL_MSG_CONFIG
,
148 NLM_F_REQUEST
| NLM_F_ACK
);
149 nf
= znl_push(zb
, sizeof(*nf
));
150 *nf
= (struct nfgenmsg
){
151 .nfgen_family
= AF_UNSPEC
,
152 .version
= NFNETLINK_V0
,
153 .res_id
= htons(group
),
155 cmd
.command
= NFULNL_CFG_CMD_BIND
;
156 znl_rta_push(zb
, NFULA_CFG_CMD
, &cmd
, sizeof(cmd
));
157 znl_nlmsg_complete(zb
, n
);
163 static void netlink_log_indication(struct nlmsghdr
*msg
, struct zbuf
*zb
)
167 struct zbuf rtapl
, pktpl
;
168 struct interface
*ifp
;
169 struct nfulnl_msg_packet_hdr
*pkthdr
= NULL
;
170 uint32_t *in_ndx
= NULL
;
172 nf
= znl_pull(zb
, sizeof(*nf
));
176 memset(&pktpl
, 0, sizeof(pktpl
));
177 while ((rta
= znl_rta_pull(zb
, &rtapl
)) != NULL
) {
178 switch (rta
->rta_type
) {
179 case NFULA_PACKET_HDR
:
180 pkthdr
= znl_pull(&rtapl
, sizeof(*pkthdr
));
182 case NFULA_IFINDEX_INDEV
:
183 in_ndx
= znl_pull(&rtapl
, sizeof(*in_ndx
));
188 /* NFULA_HWHDR exists and is supposed to contain source
189 * hardware address. However, for ip_gre it seems to be
190 * the nexthop destination address if the packet matches
195 if (!pkthdr
|| !in_ndx
|| !zbuf_used(&pktpl
))
198 ifp
= if_lookup_by_index(htonl(*in_ndx
), VRF_DEFAULT
);
202 nhrp_peer_send_indication(ifp
, htons(pkthdr
->hw_protocol
), &pktpl
);
205 static int netlink_log_recv(struct thread
*t
)
207 uint8_t buf
[ZNL_BUFFER_SIZE
];
208 int fd
= THREAD_FD(t
);
209 struct zbuf payload
, zb
;
212 netlink_log_thread
= NULL
;
214 zbuf_init(&zb
, buf
, sizeof(buf
), 0);
215 while (zbuf_recv(&zb
, fd
) > 0) {
216 while ((n
= znl_nlmsg_pull(&zb
, &payload
)) != 0) {
217 debugf(NHRP_DEBUG_KERNEL
,
218 "Netlink-log: Received msg_type %u, msg_flags %u",
219 n
->nlmsg_type
, n
->nlmsg_flags
);
220 switch (n
->nlmsg_type
) {
221 case (NFNL_SUBSYS_ULOG
<< 8) | NFULNL_MSG_PACKET
:
222 netlink_log_indication(n
, &payload
);
228 thread_add_read(master
, netlink_log_recv
, 0, netlink_log_fd
,
229 &netlink_log_thread
);
234 void netlink_set_nflog_group(int nlgroup
)
236 if (netlink_log_fd
>= 0) {
237 THREAD_OFF(netlink_log_thread
);
238 close(netlink_log_fd
);
241 netlink_nflog_group
= nlgroup
;
243 netlink_log_fd
= znl_open(NETLINK_NETFILTER
, 0);
244 if (netlink_log_fd
< 0)
247 netlink_log_register(netlink_log_fd
, nlgroup
);
248 thread_add_read(master
, netlink_log_recv
, 0, netlink_log_fd
,
249 &netlink_log_thread
);
253 void netlink_init(void)
255 netlink_req_fd
= znl_open(NETLINK_ROUTE
, 0);
256 if (netlink_req_fd
< 0)
259 netlink_listen_fd
= znl_open(NETLINK_ROUTE
, RTMGRP_NEIGH
);
260 if (netlink_listen_fd
< 0)
263 thread_add_read(master
, netlink_route_recv
, 0, netlink_listen_fd
, NULL
);
266 int netlink_configure_arp(unsigned int ifindex
, int pf
)
271 struct zbuf
*zb
= zbuf_alloc(512);
274 n
= znl_nlmsg_push(zb
, RTM_SETNEIGHTBL
, NLM_F_REQUEST
| NLM_F_REPLACE
);
275 ndtm
= znl_push(zb
, sizeof(*ndtm
));
276 *ndtm
= (struct ndtmsg
){
280 znl_rta_push(zb
, NDTA_NAME
, pf
== AF_INET
? "arp_cache" : "ndisc_cache",
283 rta
= znl_rta_nested_push(zb
, NDTA_PARMS
);
284 znl_rta_push_u32(zb
, NDTPA_IFINDEX
, ifindex
);
285 znl_rta_push_u32(zb
, NDTPA_APP_PROBES
, 1);
286 znl_rta_push_u32(zb
, NDTPA_MCAST_PROBES
, 0);
287 znl_rta_push_u32(zb
, NDTPA_UCAST_PROBES
, 0);
288 znl_rta_nested_complete(zb
, rta
);
290 znl_nlmsg_complete(zb
, n
);
291 r
= zbuf_send(zb
, netlink_req_fd
);
292 zbuf_recv(zb
, netlink_req_fd
);