1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <stdbool.h> 5 #include <err.h> 6 #include <errno.h> 7 #include <netdb.h> 8 9 #include <sys/bitcount.h> 10 #include <sys/param.h> 11 #include <sys/linker.h> 12 #include <sys/module.h> 13 #include <sys/socket.h> 14 #include <sys/sysctl.h> 15 #include <sys/time.h> 16 #include <sys/types.h> 17 18 #include <netinet/in.h> 19 #include <arpa/inet.h> 20 21 #include <net/ethernet.h> 22 #include <net/if.h> 23 #include <net/if_dl.h> 24 #include <net/if_types.h> 25 #include <netlink/netlink.h> 26 #include <netlink/netlink_route.h> 27 #include <netlink/netlink_snl.h> 28 #include <netlink/netlink_snl_route.h> 29 #include <netlink/netlink_snl_route_compat.h> 30 #include <netlink/netlink_snl_route_parsers.h> 31 32 #include <libxo/xo.h> 33 #include "arp.h" 34 35 #define RTF_ANNOUNCE RTF_PROTO2 36 37 static void 38 nl_init_socket(struct snl_state *ss) 39 { 40 if (snl_init(ss, NETLINK_ROUTE)) 41 return; 42 43 if (modfind("netlink") == -1 && errno == ENOENT) { 44 /* Try to load */ 45 if (kldload("netlink") == -1) 46 err(1, "netlink is not loaded and load attempt failed"); 47 if (snl_init(ss, NETLINK_ROUTE)) 48 return; 49 } 50 51 err(1, "unable to open netlink socket"); 52 } 53 54 static bool 55 get_link_info(struct snl_state *ss, uint32_t ifindex, 56 struct snl_parsed_link_simple *link) 57 { 58 struct snl_writer nw; 59 60 snl_init_writer(ss, &nw); 61 62 struct nlmsghdr *hdr = snl_create_msg_request(&nw, RTM_GETLINK); 63 struct ifinfomsg *ifmsg = snl_reserve_msg_object(&nw, struct ifinfomsg); 64 if (ifmsg != NULL) 65 ifmsg->ifi_index = ifindex; 66 if (!snl_finalize_msg(&nw) || !snl_send_message(ss, hdr)) 67 return (false); 68 69 hdr = snl_read_reply(ss, hdr->nlmsg_seq); 70 71 if (hdr == NULL || hdr->nlmsg_type != RTM_NEWLINK) 72 return (false); 73 74 if (!snl_parse_nlmsg(ss, hdr, &snl_rtm_link_parser_simple, link)) 75 return (false); 76 77 return (true); 78 } 79 80 81 82 static bool 83 has_l2(struct snl_state *ss, uint32_t ifindex) 84 { 85 struct snl_parsed_link_simple link = {}; 86 87 if (!get_link_info(ss, ifindex, &link)) 88 return (false); 89 90 return (valid_type(link.ifi_type) != 0); 91 } 92 93 static uint32_t 94 get_myfib(void) 95 { 96 uint32_t fibnum = 0; 97 size_t len = sizeof(fibnum); 98 99 sysctlbyname("net.my_fibnum", (void *)&fibnum, &len, NULL, 0); 100 101 return (fibnum); 102 } 103 104 static int 105 guess_ifindex(struct snl_state *ss, uint32_t fibnum, struct in_addr addr) 106 { 107 struct snl_writer nw; 108 109 snl_init_writer(ss, &nw); 110 111 struct nlmsghdr *hdr = snl_create_msg_request(&nw, RTM_GETROUTE); 112 struct rtmsg *rtm = snl_reserve_msg_object(&nw, struct rtmsg); 113 rtm->rtm_family = AF_INET; 114 115 struct sockaddr_in dst = { .sin_family = AF_INET, .sin_addr = addr }; 116 snl_add_msg_attr_ip(&nw, RTA_DST, (struct sockaddr *)&dst); 117 snl_add_msg_attr_u32(&nw, RTA_TABLE, fibnum); 118 119 if (!snl_finalize_msg(&nw) || !snl_send_message(ss, hdr)) 120 return (0); 121 122 hdr = snl_read_reply(ss, hdr->nlmsg_seq); 123 124 if (hdr->nlmsg_type != NL_RTM_NEWROUTE) { 125 /* No route found, unable to guess ifindex */ 126 return (0); 127 } 128 129 struct snl_parsed_route r = {}; 130 if (!snl_parse_nlmsg(ss, hdr, &snl_rtm_route_parser, &r)) 131 return (0); 132 133 if (r.rta_multipath.num_nhops > 0 || (r.rta_rtflags & RTF_GATEWAY)) 134 return (0); 135 136 /* Check if the interface is of supported type */ 137 if (has_l2(ss, r.rta_oif)) 138 return (r.rta_oif); 139 140 /* Check the case when we matched the loopback route for P2P */ 141 snl_init_writer(ss, &nw); 142 hdr = snl_create_msg_request(&nw, RTM_GETNEXTHOP); 143 snl_reserve_msg_object(&nw, struct nhmsg); 144 145 int off = snl_add_msg_attr_nested(&nw, NHA_FREEBSD); 146 snl_add_msg_attr_u32(&nw, NHAF_KID, r.rta_knh_id); 147 snl_add_msg_attr_u8(&nw, NHAF_FAMILY, AF_INET); 148 snl_add_msg_attr_u32(&nw, NHAF_TABLE, fibnum); 149 snl_end_attr_nested(&nw, off); 150 151 if (!snl_finalize_msg(&nw) || !snl_send_message(ss, hdr)) 152 return (0); 153 154 hdr = snl_read_reply(ss, hdr->nlmsg_seq); 155 156 if (hdr->nlmsg_type != NL_RTM_NEWNEXTHOP) { 157 /* No nexthop found, unable to guess ifindex */ 158 return (0); 159 } 160 161 struct snl_parsed_nhop nh = {}; 162 if (!snl_parse_nlmsg(ss, hdr, &snl_nhmsg_parser, &nh)) 163 return (0); 164 165 return (nh.nhaf_aif); 166 } 167 168 static uint32_t 169 fix_ifindex(struct snl_state *ss, uint32_t ifindex, struct in_addr addr) 170 { 171 if (ifindex == 0) 172 ifindex = guess_ifindex(ss, get_myfib(), addr); 173 return (ifindex); 174 } 175 176 static void 177 print_entry(struct snl_parsed_neigh *neigh, struct snl_parsed_link_simple *link) 178 { 179 const char *host; 180 struct hostent *hp; 181 struct sockaddr_in *addr = (struct sockaddr_in *)neigh->nda_dst; 182 183 xo_open_instance("arp-cache"); 184 185 if (!opts.nflag) 186 hp = gethostbyaddr((caddr_t)&(addr->sin_addr), 187 sizeof(addr->sin_addr), AF_INET); 188 else 189 hp = 0; 190 if (hp) 191 host = hp->h_name; 192 else { 193 host = "?"; 194 if (h_errno == TRY_AGAIN) 195 opts.nflag = true; 196 } 197 xo_emit("{:hostname/%s} ({:ip-address/%s}) at ", host, 198 inet_ntoa(addr->sin_addr)); 199 if (neigh->nda_lladdr != NULL) { 200 struct sockaddr_dl sdl = { 201 .sdl_family = AF_LINK, 202 .sdl_type = link->ifi_type, 203 .sdl_len = sizeof(struct sockaddr_dl), 204 .sdl_alen = NLA_DATA_LEN(neigh->nda_lladdr), 205 }; 206 memcpy(sdl.sdl_data, NLA_DATA(neigh->nda_lladdr), sdl.sdl_alen); 207 208 if ((sdl.sdl_type == IFT_ETHER || 209 sdl.sdl_type == IFT_L2VLAN || 210 sdl.sdl_type == IFT_BRIDGE) && 211 sdl.sdl_alen == ETHER_ADDR_LEN) 212 xo_emit("{:mac-address/%s}", 213 ether_ntoa((struct ether_addr *)LLADDR(&sdl))); 214 else { 215 216 xo_emit("{:mac-address/%s}", link_ntoa(&sdl)); 217 } 218 } else 219 xo_emit("{d:/(incomplete)}{en:incomplete/true}"); 220 xo_emit(" on {:interface/%s}", link->ifla_ifname); 221 222 if (neigh->ndaf_next_ts == 0) 223 xo_emit("{d:/ permanent}{en:permanent/true}"); 224 else { 225 time_t expire_time; 226 struct timeval now; 227 228 gettimeofday(&now, 0); 229 if ((expire_time = neigh->ndaf_next_ts - now.tv_sec) > 0) 230 xo_emit(" expires in {:expires/%d} seconds", 231 (int)expire_time); 232 else 233 xo_emit("{d:/ expired}{en:expired/true}"); 234 } 235 236 if (neigh->ndm_flags & NTF_PROXY) 237 xo_emit("{d:/ published}{en:published/true}"); 238 239 switch(link->ifi_type) { 240 case IFT_ETHER: 241 xo_emit(" [{:type/ethernet}]"); 242 break; 243 case IFT_FDDI: 244 xo_emit(" [{:type/fddi}]"); 245 break; 246 case IFT_ATM: 247 xo_emit(" [{:type/atm}]"); 248 break; 249 case IFT_L2VLAN: 250 xo_emit(" [{:type/vlan}]"); 251 break; 252 case IFT_IEEE1394: 253 xo_emit(" [{:type/firewire}]"); 254 break; 255 case IFT_BRIDGE: 256 xo_emit(" [{:type/bridge}]"); 257 break; 258 case IFT_INFINIBAND: 259 xo_emit(" [{:type/infiniband}]"); 260 break; 261 default: 262 break; 263 } 264 265 xo_emit("\n"); 266 267 xo_close_instance("arp-cache"); 268 } 269 270 int 271 print_entries_nl(uint32_t ifindex, struct in_addr addr) 272 { 273 struct snl_state ss_req = {}, ss_cmd = {}; 274 struct snl_parsed_link_simple link = {}; 275 struct snl_writer nw; 276 277 nl_init_socket(&ss_req); 278 snl_init_writer(&ss_req, &nw); 279 280 struct nlmsghdr *hdr = snl_create_msg_request(&nw, RTM_GETNEIGH); 281 struct ndmsg *ndmsg = snl_reserve_msg_object(&nw, struct ndmsg); 282 if (ndmsg != NULL) { 283 ndmsg->ndm_family = AF_INET; 284 ndmsg->ndm_ifindex = ifindex; 285 } 286 287 if (!snl_finalize_msg(&nw) || !snl_send_message(&ss_req, hdr)) { 288 snl_free(&ss_req); 289 return (0); 290 } 291 292 uint32_t nlmsg_seq = hdr->nlmsg_seq; 293 struct snl_errmsg_data e = {}; 294 int count = 0; 295 nl_init_socket(&ss_cmd); 296 297 while ((hdr = snl_read_reply_multi(&ss_req, nlmsg_seq, &e)) != NULL) { 298 struct snl_parsed_neigh neigh = {}; 299 300 if (!snl_parse_nlmsg(&ss_req, hdr, &snl_rtm_neigh_parser, &neigh)) 301 continue; 302 303 if (neigh.nda_ifindex != link.ifi_index) { 304 snl_clear_lb(&ss_cmd); 305 memset(&link, 0, sizeof(link)); 306 if (!get_link_info(&ss_cmd, neigh.nda_ifindex, &link)) 307 continue; 308 } 309 310 print_entry(&neigh, &link); 311 count++; 312 snl_clear_lb(&ss_req); 313 } 314 315 snl_free(&ss_req); 316 snl_free(&ss_cmd); 317 318 return (count); 319 } 320 321 int 322 delete_nl(uint32_t ifindex, char *host) 323 { 324 struct snl_state ss = {}; 325 struct snl_writer nw; 326 struct sockaddr_in *dst; 327 328 dst = getaddr(host); 329 if (dst == NULL) 330 return (1); 331 332 nl_init_socket(&ss); 333 334 ifindex = fix_ifindex(&ss, ifindex, dst->sin_addr); 335 if (ifindex == 0) { 336 xo_warnx("delete: cannot locate %s", host); 337 snl_free(&ss); 338 return (0); 339 } 340 341 snl_init_writer(&ss, &nw); 342 struct nlmsghdr *hdr = snl_create_msg_request(&nw, RTM_DELNEIGH); 343 struct ndmsg *ndmsg = snl_reserve_msg_object(&nw, struct ndmsg); 344 if (ndmsg != NULL) { 345 ndmsg->ndm_family = AF_INET; 346 ndmsg->ndm_ifindex = ifindex; 347 } 348 snl_add_msg_attr_ip(&nw, NDA_DST, (struct sockaddr *)dst); 349 350 if (!snl_finalize_msg(&nw) || !snl_send_message(&ss, hdr)) { 351 snl_free(&ss); 352 return (1); 353 } 354 355 struct snl_errmsg_data e = {}; 356 snl_read_reply_code(&ss, hdr->nlmsg_seq, &e); 357 if (e.error != 0) { 358 if (e.error_str != NULL) 359 xo_warnx("delete %s: %s (%s)", host, strerror(e.error), e.error_str); 360 else 361 xo_warnx("delete %s: %s", host, strerror(e.error)); 362 } else 363 printf("%s (%s) deleted\n", host, inet_ntoa(dst->sin_addr)); 364 365 snl_free(&ss); 366 367 return (e.error != 0); 368 } 369 370 int 371 set_nl(uint32_t ifindex, struct sockaddr_in *dst, struct sockaddr_dl *sdl, char *host) 372 { 373 struct snl_state ss = {}; 374 struct snl_writer nw; 375 376 nl_init_socket(&ss); 377 378 ifindex = fix_ifindex(&ss, ifindex, dst->sin_addr); 379 if (ifindex == 0) { 380 xo_warnx("delete: cannot locate %s", host); 381 snl_free(&ss); 382 return (0); 383 } 384 385 if (opts.expire_time != 0) 386 opts.flags &= ~RTF_STATIC; 387 388 snl_init_writer(&ss, &nw); 389 struct nlmsghdr *hdr = snl_create_msg_request(&nw, RTM_NEWNEIGH); 390 hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE; 391 struct ndmsg *ndmsg = snl_reserve_msg_object(&nw, struct ndmsg); 392 if (ndmsg != NULL) { 393 uint8_t nl_flags = 0; 394 395 ndmsg->ndm_family = AF_INET; 396 ndmsg->ndm_ifindex = ifindex; 397 ndmsg->ndm_state = (opts.flags & RTF_STATIC) ? NUD_PERMANENT : NUD_NONE; 398 399 if (opts.flags & RTF_ANNOUNCE) 400 nl_flags |= NTF_PROXY; 401 if (opts.flags & RTF_STATIC) 402 nl_flags |= NTF_STICKY; 403 ndmsg->ndm_flags = nl_flags; 404 } 405 snl_add_msg_attr_ip(&nw, NDA_DST, (struct sockaddr *)dst); 406 snl_add_msg_attr(&nw, NDA_LLADDR, sdl->sdl_alen, LLADDR(sdl)); 407 408 if (opts.expire_time != 0) { 409 struct timeval now; 410 411 gettimeofday(&now, 0); 412 int off = snl_add_msg_attr_nested(&nw, NDA_FREEBSD); 413 snl_add_msg_attr_u32(&nw, NDAF_NEXT_STATE_TS, now.tv_sec + opts.expire_time); 414 snl_end_attr_nested(&nw, off); 415 } 416 417 if (!snl_finalize_msg(&nw) || !snl_send_message(&ss, hdr)) { 418 snl_free(&ss); 419 return (1); 420 } 421 422 struct snl_errmsg_data e = {}; 423 snl_read_reply_code(&ss, hdr->nlmsg_seq, &e); 424 if (e.error != 0) { 425 if (e.error_str != NULL) 426 xo_warnx("set: %s: %s (%s)", host, strerror(e.error), e.error_str); 427 else 428 xo_warnx("set %s: %s", host, strerror(e.error)); 429 } 430 snl_free(&ss); 431 432 return (e.error != 0); 433 } 434 435