+
+static bool xrtnl_addr_set(struct rtnl_addr *ra, uint32_t addr, int (*cb)(struct rtnl_addr*, struct nl_addr*))
+{
+ int err;
+ struct nl_addr *na = nl_addr_build(AF_INET, &addr, 4);
+
+ if (!na) {
+ xperror("nl_addr_build");
+ return false;
+ }
+
+ if ((err = cb(ra, na)) != 0 && verbosity) {
+ nl_perror(err, __func__);
+ }
+ nl_addr_put(na);
+
+ return true;
+}
+
+static struct nl_sock *xnl_socket_route()
+{
+ int err;
+ struct nl_sock *sk = nl_socket_alloc();
+ if (sk) {
+ if (!(err = nl_connect(sk, NETLINK_ROUTE))) {
+ return sk;
+ }
+ nl_socket_free(sk);
+ nl_perror(err, "nl_connect");
+ } else {
+ xperror("nl_socket_alloc");
+ }
+
+ return NULL;
+}
+
+static bool intf_add_del_ip(const char *intf, uint32_t ipaddr, uint32_t ipmask, bool add)
+{
+ struct rtnl_addr *ra = NULL;
+ struct nl_sock *sk = NULL;
+ int err = 1;
+
+ if (!(sk = xnl_socket_route())) {
+ return false;
+ }
+
+ if (!(ra = rtnl_addr_alloc())) {
+ xperror("rtnl_addr_alloc");
+ goto out;
+ }
+
+ rtnl_addr_set_ifindex(ra, if_nametoindex(intf));
+ rtnl_addr_set_prefixlen(ra, bitcount(ipmask));
+
+ if (!xrtnl_addr_set(ra, (ipaddr & ipmask) | ~ipmask, &rtnl_addr_set_broadcast)
+ || !xrtnl_addr_set(ra, ipaddr, &rtnl_addr_set_local)) {
+ goto out;
+ }
+
+ if ((err = add ? rtnl_addr_add(sk, ra, 0) : rtnl_addr_delete(sk, ra, 0)) < 0) {
+ if (add && err == -NLE_EXIST) {
+ err = 0;
+ } else if (add || verbosity > 1) {
+ nl_perror(err, add ? "rtnl_addr_add" : "rtnl_addr_delete");
+ }
+ }
+
+out:
+ rtnl_addr_put(ra);
+ nl_socket_free(sk);
+
+ return !err;
+}
+
+static bool intf_add_del_arp(const char *intf, uint32_t ipaddr, uint8_t *hwaddr, bool add)
+{
+ struct nl_sock *sk;
+ struct rtnl_neigh *neigh;
+ struct nl_addr *mac, *ip;
+ int err = 1;
+
+ sk = NULL;
+ neigh = NULL;
+ mac = ip = NULL;
+
+ if (!(sk = xnl_socket_route())) {
+ goto out;
+ }
+
+ if (!(neigh = rtnl_neigh_alloc())) {
+ xperror("rtnl_neigh_alloc");
+ goto out;
+ }
+
+ if (!(mac = nl_addr_build(AF_PACKET, hwaddr, 6))) {
+ xperror("nl_addr_build");
+ goto out;
+ }
+
+ if (!(ip = nl_addr_build(AF_INET, &ipaddr, 4))) {
+ xperror("nl_addr_build");
+ goto out;
+ }
+
+ rtnl_neigh_set_ifindex(neigh, if_nametoindex(intf));
+ rtnl_neigh_set_dst(neigh, ip);
+
+ err = rtnl_neigh_delete(sk, neigh, 0);
+
+ if (add) {
+ rtnl_neigh_set_lladdr(neigh, mac);
+ rtnl_neigh_set_state(neigh, NUD_PERMANENT);
+ system("arp -an");
+ err = rtnl_neigh_add(sk, neigh, NLM_F_CREATE);
+ system("arp -an");
+ }
+
+ if (err && (add || verbosity > 1)) {
+ nl_perror(err, add ? "rtnl_neigh_add" : "rtnl_neigh_delete");
+ }
+
+out:
+ nl_addr_put(ip);
+ nl_addr_put(mac);
+ rtnl_neigh_put(neigh);
+ nl_socket_free(sk);
+
+ return !err;
+}
+