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.
16 #include <netinet/if_ether.h>
17 #include <linux/netlink.h>
18 #include <linux/neighbour.h>
19 #include <linux/netfilter/nfnetlink_log.h>
26 int netlink_req_fd
= -1;
27 int netlink_nflog_group
;
28 static int netlink_log_fd
= -1;
29 static struct thread
*netlink_log_thread
;
30 static int netlink_listen_fd
= -1;
32 typedef void (*netlink_dispatch_f
)(struct nlmsghdr
*msg
, struct zbuf
*zb
);
34 void netlink_update_binding(struct interface
*ifp
, union sockunion
*proto
,
35 union sockunion
*nbma
)
39 struct zbuf
*zb
= zbuf_alloc(512);
41 n
= znl_nlmsg_push(zb
, nbma
? RTM_NEWNEIGH
: RTM_DELNEIGH
,
42 NLM_F_REQUEST
| NLM_F_REPLACE
| NLM_F_CREATE
);
43 ndm
= znl_push(zb
, sizeof(*ndm
));
44 *ndm
= (struct ndmsg
){
45 .ndm_family
= sockunion_family(proto
),
46 .ndm_ifindex
= ifp
->ifindex
,
47 .ndm_type
= RTN_UNICAST
,
48 .ndm_state
= nbma
? NUD_REACHABLE
: NUD_FAILED
,
50 znl_rta_push(zb
, NDA_DST
, sockunion_get_addr(proto
),
51 family2addrsize(sockunion_family(proto
)));
53 znl_rta_push(zb
, NDA_LLADDR
, sockunion_get_addr(nbma
),
54 family2addrsize(sockunion_family(nbma
)));
55 znl_nlmsg_complete(zb
, n
);
56 zbuf_send(zb
, netlink_req_fd
);
57 zbuf_recv(zb
, netlink_req_fd
);
61 static void netlink_neigh_msg(struct nlmsghdr
*msg
, struct zbuf
*zb
)
66 struct interface
*ifp
;
70 char buf
[SU_ADDRSTRLEN
];
73 ndm
= znl_pull(zb
, sizeof(*ndm
));
77 sockunion_family(&addr
) = AF_UNSPEC
;
78 while ((rta
= znl_rta_pull(zb
, &payload
)) != NULL
) {
79 len
= zbuf_used(&payload
);
80 switch (rta
->rta_type
) {
82 sockunion_set(&addr
, ndm
->ndm_family
,
83 zbuf_pulln(&payload
, len
), len
);
88 ifp
= if_lookup_by_index(ndm
->ndm_ifindex
, VRF_DEFAULT
);
89 if (!ifp
|| sockunion_family(&addr
) == AF_UNSPEC
)
92 c
= nhrp_cache_get(ifp
, &addr
, 0);
96 if (msg
->nlmsg_type
== RTM_GETNEIGH
) {
97 debugf(NHRP_DEBUG_KERNEL
, "Netlink: who-has %s dev %s",
98 sockunion2str(&addr
, buf
, sizeof buf
), ifp
->name
);
100 if (c
->cur
.type
>= NHRP_CACHE_CACHED
) {
101 nhrp_cache_set_used(c
, 1);
102 netlink_update_binding(ifp
, &addr
,
103 &c
->cur
.peer
->vc
->remote
.nbma
);
106 debugf(NHRP_DEBUG_KERNEL
, "Netlink: update %s dev %s nud %x",
107 sockunion2str(&addr
, buf
, sizeof buf
), ifp
->name
,
110 state
= (msg
->nlmsg_type
== RTM_NEWNEIGH
) ? ndm
->ndm_state
112 nhrp_cache_set_used(c
, state
== NUD_REACHABLE
);
116 static int netlink_route_recv(struct thread
*t
)
118 uint8_t buf
[ZNL_BUFFER_SIZE
];
119 int fd
= THREAD_FD(t
);
120 struct zbuf payload
, zb
;
123 zbuf_init(&zb
, buf
, sizeof(buf
), 0);
124 while (zbuf_recv(&zb
, fd
) > 0) {
125 while ((n
= znl_nlmsg_pull(&zb
, &payload
)) != NULL
) {
126 debugf(NHRP_DEBUG_KERNEL
,
127 "Netlink: Received msg_type %u, msg_flags %u",
128 n
->nlmsg_type
, n
->nlmsg_flags
);
129 switch (n
->nlmsg_type
) {
133 netlink_neigh_msg(n
, &payload
);
139 thread_add_read(master
, netlink_route_recv
, 0, fd
, NULL
);
144 static void netlink_log_register(int fd
, int group
)
148 struct nfulnl_msg_config_cmd cmd
;
149 struct zbuf
*zb
= zbuf_alloc(512);
151 n
= znl_nlmsg_push(zb
, (NFNL_SUBSYS_ULOG
<< 8) | NFULNL_MSG_CONFIG
,
152 NLM_F_REQUEST
| NLM_F_ACK
);
153 nf
= znl_push(zb
, sizeof(*nf
));
154 *nf
= (struct nfgenmsg
){
155 .nfgen_family
= AF_UNSPEC
,
156 .version
= NFNETLINK_V0
,
157 .res_id
= htons(group
),
159 cmd
.command
= NFULNL_CFG_CMD_BIND
;
160 znl_rta_push(zb
, NFULA_CFG_CMD
, &cmd
, sizeof(cmd
));
161 znl_nlmsg_complete(zb
, n
);
167 static void netlink_log_indication(struct nlmsghdr
*msg
, struct zbuf
*zb
)
171 struct zbuf rtapl
, pktpl
;
172 struct interface
*ifp
;
173 struct nfulnl_msg_packet_hdr
*pkthdr
= NULL
;
174 uint32_t *in_ndx
= NULL
;
176 nf
= znl_pull(zb
, sizeof(*nf
));
180 memset(&pktpl
, 0, sizeof(pktpl
));
181 while ((rta
= znl_rta_pull(zb
, &rtapl
)) != NULL
) {
182 switch (rta
->rta_type
) {
183 case NFULA_PACKET_HDR
:
184 pkthdr
= znl_pull(&rtapl
, sizeof(*pkthdr
));
186 case NFULA_IFINDEX_INDEV
:
187 in_ndx
= znl_pull(&rtapl
, sizeof(*in_ndx
));
192 /* NFULA_HWHDR exists and is supposed to contain source
193 * hardware address. However, for ip_gre it seems to be
194 * the nexthop destination address if the packet matches
199 if (!pkthdr
|| !in_ndx
|| !zbuf_used(&pktpl
))
202 ifp
= if_lookup_by_index(htonl(*in_ndx
), VRF_DEFAULT
);
206 nhrp_peer_send_indication(ifp
, htons(pkthdr
->hw_protocol
), &pktpl
);
209 static int netlink_log_recv(struct thread
*t
)
211 uint8_t buf
[ZNL_BUFFER_SIZE
];
212 int fd
= THREAD_FD(t
);
213 struct zbuf payload
, zb
;
216 netlink_log_thread
= NULL
;
218 zbuf_init(&zb
, buf
, sizeof(buf
), 0);
219 while (zbuf_recv(&zb
, fd
) > 0) {
220 while ((n
= znl_nlmsg_pull(&zb
, &payload
)) != NULL
) {
221 debugf(NHRP_DEBUG_KERNEL
,
222 "Netlink-log: Received msg_type %u, msg_flags %u",
223 n
->nlmsg_type
, n
->nlmsg_flags
);
224 switch (n
->nlmsg_type
) {
225 case (NFNL_SUBSYS_ULOG
<< 8) | NFULNL_MSG_PACKET
:
226 netlink_log_indication(n
, &payload
);
232 thread_add_read(master
, netlink_log_recv
, 0, netlink_log_fd
,
233 &netlink_log_thread
);
238 void netlink_set_nflog_group(int nlgroup
)
240 if (netlink_log_fd
>= 0) {
241 THREAD_OFF(netlink_log_thread
);
242 close(netlink_log_fd
);
245 netlink_nflog_group
= nlgroup
;
247 netlink_log_fd
= znl_open(NETLINK_NETFILTER
, 0);
248 if (netlink_log_fd
< 0)
251 netlink_log_register(netlink_log_fd
, nlgroup
);
252 thread_add_read(master
, netlink_log_recv
, 0, netlink_log_fd
,
253 &netlink_log_thread
);
257 void netlink_init(void)
259 netlink_req_fd
= znl_open(NETLINK_ROUTE
, 0);
260 if (netlink_req_fd
< 0)
263 netlink_listen_fd
= znl_open(NETLINK_ROUTE
, RTMGRP_NEIGH
);
264 if (netlink_listen_fd
< 0)
267 thread_add_read(master
, netlink_route_recv
, 0, netlink_listen_fd
, NULL
);
270 int netlink_configure_arp(unsigned int ifindex
, int pf
)
275 struct zbuf
*zb
= zbuf_alloc(512);
278 n
= znl_nlmsg_push(zb
, RTM_SETNEIGHTBL
, NLM_F_REQUEST
| NLM_F_REPLACE
);
279 ndtm
= znl_push(zb
, sizeof(*ndtm
));
280 *ndtm
= (struct ndtmsg
){
284 znl_rta_push(zb
, NDTA_NAME
, pf
== AF_INET
? "arp_cache" : "ndisc_cache",
287 rta
= znl_rta_nested_push(zb
, NDTA_PARMS
);
288 znl_rta_push_u32(zb
, NDTPA_IFINDEX
, ifindex
);
289 znl_rta_push_u32(zb
, NDTPA_APP_PROBES
, 1);
290 znl_rta_push_u32(zb
, NDTPA_MCAST_PROBES
, 0);
291 znl_rta_push_u32(zb
, NDTPA_UCAST_PROBES
, 0);
292 znl_rta_nested_complete(zb
, rta
);
294 znl_nlmsg_complete(zb
, n
);
295 r
= zbuf_send(zb
, netlink_req_fd
);
296 zbuf_recv(zb
, netlink_req_fd
);