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
, union sockunion
*nbma
)
34 struct zbuf
*zb
= zbuf_alloc(512);
36 n
= znl_nlmsg_push(zb
, nbma
? RTM_NEWNEIGH
: RTM_DELNEIGH
, NLM_F_REQUEST
| NLM_F_REPLACE
| NLM_F_CREATE
);
37 ndm
= znl_push(zb
, sizeof(*ndm
));
38 *ndm
= (struct ndmsg
) {
39 .ndm_family
= sockunion_family(proto
),
40 .ndm_ifindex
= ifp
->ifindex
,
41 .ndm_type
= RTN_UNICAST
,
42 .ndm_state
= nbma
? NUD_REACHABLE
: NUD_FAILED
,
44 znl_rta_push(zb
, NDA_DST
, sockunion_get_addr(proto
), family2addrsize(sockunion_family(proto
)));
46 znl_rta_push(zb
, NDA_LLADDR
, sockunion_get_addr(nbma
), family2addrsize(sockunion_family(nbma
)));
47 znl_nlmsg_complete(zb
, n
);
48 zbuf_send(zb
, netlink_req_fd
);
49 zbuf_recv(zb
, netlink_req_fd
);
53 static void netlink_neigh_msg(struct nlmsghdr
*msg
, struct zbuf
*zb
)
58 struct interface
*ifp
;
62 char buf
[SU_ADDRSTRLEN
];
65 ndm
= znl_pull(zb
, sizeof(*ndm
));
68 sockunion_family(&addr
) = AF_UNSPEC
;
69 while ((rta
= znl_rta_pull(zb
, &payload
)) != NULL
) {
70 len
= zbuf_used(&payload
);
71 switch (rta
->rta_type
) {
73 sockunion_set(&addr
, ndm
->ndm_family
, zbuf_pulln(&payload
, len
), len
);
78 ifp
= if_lookup_by_index(ndm
->ndm_ifindex
, VRF_DEFAULT
);
79 if (!ifp
|| sockunion_family(&addr
) == AF_UNSPEC
)
82 c
= nhrp_cache_get(ifp
, &addr
, 0);
86 if (msg
->nlmsg_type
== RTM_GETNEIGH
) {
87 debugf(NHRP_DEBUG_KERNEL
, "Netlink: who-has %s dev %s",
88 sockunion2str(&addr
, buf
, sizeof buf
),
91 if (c
->cur
.type
>= NHRP_CACHE_CACHED
) {
92 nhrp_cache_set_used(c
, 1);
93 netlink_update_binding(ifp
, &addr
, &c
->cur
.peer
->vc
->remote
.nbma
);
96 debugf(NHRP_DEBUG_KERNEL
, "Netlink: update %s dev %s nud %x",
97 sockunion2str(&addr
, buf
, sizeof buf
),
98 ifp
->name
, ndm
->ndm_state
);
100 state
= (msg
->nlmsg_type
== RTM_NEWNEIGH
) ? ndm
->ndm_state
: NUD_FAILED
;
101 nhrp_cache_set_used(c
, state
== NUD_REACHABLE
);
105 static int netlink_route_recv(struct thread
*t
)
107 uint8_t buf
[ZNL_BUFFER_SIZE
];
108 int fd
= THREAD_FD(t
);
109 struct zbuf payload
, zb
;
112 zbuf_init(&zb
, buf
, sizeof(buf
), 0);
113 while (zbuf_recv(&zb
, fd
) > 0) {
114 while ((n
= znl_nlmsg_pull(&zb
, &payload
)) != 0) {
115 debugf(NHRP_DEBUG_KERNEL
, "Netlink: Received msg_type %u, msg_flags %u",
116 n
->nlmsg_type
, n
->nlmsg_flags
);
117 switch (n
->nlmsg_type
) {
121 netlink_neigh_msg(n
, &payload
);
127 thread_add_read(master
, netlink_route_recv
, 0, fd
, NULL
);
132 static void netlink_log_register(int fd
, int group
)
136 struct nfulnl_msg_config_cmd cmd
;
137 struct zbuf
*zb
= zbuf_alloc(512);
139 n
= znl_nlmsg_push(zb
, (NFNL_SUBSYS_ULOG
<<8) | NFULNL_MSG_CONFIG
, NLM_F_REQUEST
| NLM_F_ACK
);
140 nf
= znl_push(zb
, sizeof(*nf
));
141 *nf
= (struct nfgenmsg
) {
142 .nfgen_family
= AF_UNSPEC
,
143 .version
= NFNETLINK_V0
,
144 .res_id
= htons(group
),
146 cmd
.command
= NFULNL_CFG_CMD_BIND
;
147 znl_rta_push(zb
, NFULA_CFG_CMD
, &cmd
, sizeof(cmd
));
148 znl_nlmsg_complete(zb
, n
);
154 static void netlink_log_indication(struct nlmsghdr
*msg
, struct zbuf
*zb
)
158 struct zbuf rtapl
, pktpl
;
159 struct interface
*ifp
;
160 struct nfulnl_msg_packet_hdr
*pkthdr
= NULL
;
161 uint32_t *in_ndx
= NULL
;
163 nf
= znl_pull(zb
, sizeof(*nf
));
166 memset(&pktpl
, 0, sizeof(pktpl
));
167 while ((rta
= znl_rta_pull(zb
, &rtapl
)) != NULL
) {
168 switch (rta
->rta_type
) {
169 case NFULA_PACKET_HDR
:
170 pkthdr
= znl_pull(&rtapl
, sizeof(*pkthdr
));
172 case NFULA_IFINDEX_INDEV
:
173 in_ndx
= znl_pull(&rtapl
, sizeof(*in_ndx
));
178 /* NFULA_HWHDR exists and is supposed to contain source
179 * hardware address. However, for ip_gre it seems to be
180 * the nexthop destination address if the packet matches
185 if (!pkthdr
|| !in_ndx
|| !zbuf_used(&pktpl
))
188 ifp
= if_lookup_by_index(htonl(*in_ndx
), VRF_DEFAULT
);
192 nhrp_peer_send_indication(ifp
, htons(pkthdr
->hw_protocol
), &pktpl
);
195 static int netlink_log_recv(struct thread
*t
)
197 uint8_t buf
[ZNL_BUFFER_SIZE
];
198 int fd
= THREAD_FD(t
);
199 struct zbuf payload
, zb
;
202 netlink_log_thread
= NULL
;
204 zbuf_init(&zb
, buf
, sizeof(buf
), 0);
205 while (zbuf_recv(&zb
, fd
) > 0) {
206 while ((n
= znl_nlmsg_pull(&zb
, &payload
)) != 0) {
207 debugf(NHRP_DEBUG_KERNEL
, "Netlink-log: Received msg_type %u, msg_flags %u",
208 n
->nlmsg_type
, n
->nlmsg_flags
);
209 switch (n
->nlmsg_type
) {
210 case (NFNL_SUBSYS_ULOG
<<8) | NFULNL_MSG_PACKET
:
211 netlink_log_indication(n
, &payload
);
217 thread_add_read(master
, netlink_log_recv
, 0, netlink_log_fd
,
218 &netlink_log_thread
);
223 void netlink_set_nflog_group(int nlgroup
)
225 if (netlink_log_fd
>= 0) {
226 THREAD_OFF(netlink_log_thread
);
227 close(netlink_log_fd
);
230 netlink_nflog_group
= nlgroup
;
232 netlink_log_fd
= znl_open(NETLINK_NETFILTER
, 0);
233 netlink_log_register(netlink_log_fd
, nlgroup
);
234 thread_add_read(master
, netlink_log_recv
, 0, netlink_log_fd
,
235 &netlink_log_thread
);
239 int netlink_init(void)
241 netlink_req_fd
= znl_open(NETLINK_ROUTE
, 0);
242 netlink_listen_fd
= znl_open(NETLINK_ROUTE
, RTMGRP_NEIGH
);
243 thread_add_read(master
, netlink_route_recv
, 0, netlink_listen_fd
,
249 int netlink_configure_arp(unsigned int ifindex
, int pf
)
254 struct zbuf
*zb
= zbuf_alloc(512);
257 n
= znl_nlmsg_push(zb
, RTM_SETNEIGHTBL
, NLM_F_REQUEST
| NLM_F_REPLACE
);
258 ndtm
= znl_push(zb
, sizeof(*ndtm
));
259 *ndtm
= (struct ndtmsg
) {
263 znl_rta_push(zb
, NDTA_NAME
, pf
== AF_INET
? "arp_cache" : "ndisc_cache", 10);
265 rta
= znl_rta_nested_push(zb
, NDTA_PARMS
);
266 znl_rta_push_u32(zb
, NDTPA_IFINDEX
, ifindex
);
267 znl_rta_push_u32(zb
, NDTPA_APP_PROBES
, 1);
268 znl_rta_push_u32(zb
, NDTPA_MCAST_PROBES
, 0);
269 znl_rta_push_u32(zb
, NDTPA_UCAST_PROBES
, 0);
270 znl_rta_nested_complete(zb
, rta
);
272 znl_nlmsg_complete(zb
, n
);
273 r
= zbuf_send(zb
, netlink_req_fd
);
274 zbuf_recv(zb
, netlink_req_fd
);