1a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown/*
2a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * Copyright 2012 Daniel Drown <dan-android@drown.org>
3a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown *
4a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * Licensed under the Apache License, Version 2.0 (the "License");
5a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * you may not use this file except in compliance with the License.
6a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * You may obtain a copy of the License at
7a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown *
8a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * http://www.apache.org/licenses/LICENSE-2.0
9a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown *
10a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * Unless required by applicable law or agreed to in writing, software
11a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * distributed under the License is distributed on an "AS IS" BASIS,
12a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * See the License for the specific language governing permissions and
14a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * limitations under the License.
15a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown *
16a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * setif.c - network interface configuration
17a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown */
18a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include <errno.h>
19a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include <netinet/in.h>
20a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include <net/if.h>
21a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown
22a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include <linux/rtnetlink.h>
23a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include <netlink/handlers.h>
24a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include <netlink/msg.h>
25a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown
268a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colitti#include "logging.h"
27a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include "netlink_msg.h"
28a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown
298a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colitti#define DEBUG_OPTNAME(a) case (a): { optname = #a; break; }
308a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colitti
31a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown/* function: add_address
32a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * adds an IP address to/from an interface, returns 0 on success and <0 on failure
33a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * ifname    - name of interface to change
34a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * family    - address family (AF_INET, AF_INET6)
35a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * address   - pointer to a struct in_addr or in6_addr
36a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * prefixlen - bitlength of network (example: 24 for AF_INET's 255.255.255.0)
37a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * broadcast - broadcast address (only for AF_INET, ignored for AF_INET6)
38a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown */
39a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drownint add_address(const char *ifname, int family, const void *address, int prefixlen, const void *broadcast) {
40a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown  int retval;
41a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown  size_t addr_size;
42a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown  struct ifaddrmsg ifa;
43a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown  struct nl_msg *msg = NULL;
44a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown
45a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown  addr_size = inet_family_size(family);
46a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown  if(addr_size == 0) {
47a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown    retval = -EAFNOSUPPORT;
48a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown    goto cleanup;
49a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown  }
50a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown
51a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown  memset(&ifa, 0, sizeof(ifa));
52a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown  if (!(ifa.ifa_index = if_nametoindex(ifname))) {
53a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown    retval = -ENODEV;
54a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown    goto cleanup;
55a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown  }
56a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown  ifa.ifa_family = family;
57a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown  ifa.ifa_prefixlen = prefixlen;
58a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown  ifa.ifa_scope = RT_SCOPE_UNIVERSE;
59a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown
60a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown  msg = nlmsg_alloc_ifaddr(RTM_NEWADDR, NLM_F_ACK | NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE, &ifa);
61a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown  if(!msg) {
62a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown    retval = -ENOMEM;
63a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown    goto cleanup;
64a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown  }
65a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown
66a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown  if(nla_put(msg, IFA_LOCAL, addr_size, address) < 0) {
67a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown    retval = -ENOMEM;
68a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown    goto cleanup;
69a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown  }
70a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown  if(family == AF_INET6) {
71a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown    // AF_INET6 gets IFA_LOCAL + IFA_ADDRESS
72a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown    if(nla_put(msg, IFA_ADDRESS, addr_size, address) < 0) {
73a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown      retval = -ENOMEM;
74a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown      goto cleanup;
75a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown    }
76a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown  } else if(family == AF_INET) {
77a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown    // AF_INET gets IFA_LOCAL + IFA_BROADCAST
78a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown    if(nla_put(msg, IFA_BROADCAST, addr_size, broadcast) < 0) {
79a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown      retval = -ENOMEM;
80a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown      goto cleanup;
81a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown    }
82a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown  } else {
83a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown    retval = -EAFNOSUPPORT;
84a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown    goto cleanup;
85a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown  }
86a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown
87a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown  retval = netlink_sendrecv(msg);
88a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown
89a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drowncleanup:
90a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown  if(msg)
91a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown    nlmsg_free(msg);
92a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown
93a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown  return retval;
94a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown}
95a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown
96a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown/* function: if_up
97a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * sets interface link state to up and sets mtu, returns 0 on success and <0 on failure
98a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * ifname - interface name to change
99a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * mtu    - new mtu
100a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown */
101a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drownint if_up(const char *ifname, int mtu) {
102a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown  int retval = -1;
103a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown  struct ifinfomsg ifi;
104a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown  struct nl_msg *msg = NULL;
105a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown
106a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown  memset(&ifi, 0, sizeof(ifi));
107a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown  if (!(ifi.ifi_index = if_nametoindex(ifname))) {
108a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown    retval = -ENODEV;
109a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown    goto cleanup;
110a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown  }
111a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown  ifi.ifi_change = IFF_UP;
112a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown  ifi.ifi_flags = IFF_UP;
113a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown
114a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown  msg = nlmsg_alloc_ifinfo(RTM_SETLINK, NLM_F_ACK | NLM_F_REQUEST | NLM_F_ROOT, &ifi);
115a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown  if(!msg) {
116a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown    retval = -ENOMEM;
117a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown    goto cleanup;
118a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown  }
119a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown
120a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown  if(nla_put(msg, IFLA_MTU, 4, &mtu) < 0) {
121a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown    retval = -ENOMEM;
122a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown    goto cleanup;
123a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown  }
124a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown
125a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown  retval = netlink_sendrecv(msg);
126a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown
127a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drowncleanup:
128a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown  if(msg)
129a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown    nlmsg_free(msg);
130a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown
131a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown  return retval;
132a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown}
1338a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colitti
1348a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colittistatic int do_anycast_setsockopt(int sock, int what, struct in6_addr *addr, int ifindex) {
1358a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colitti  struct ipv6_mreq mreq = { *addr, ifindex };
1368a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colitti  char *optname;
1378a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colitti  int ret;
1388a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colitti
1398a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colitti  switch (what) {
1408a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colitti    DEBUG_OPTNAME(IPV6_JOIN_ANYCAST)
1418a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colitti    DEBUG_OPTNAME(IPV6_LEAVE_ANYCAST)
1428a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colitti    default:
1438a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colitti      optname = "???";
1448a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colitti      break;
1458a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colitti  }
1468a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colitti
1478a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colitti  ret = setsockopt(sock, SOL_IPV6, what, &mreq, sizeof(mreq));
1488a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colitti  if (ret) {
1498a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colitti    logmsg(ANDROID_LOG_ERROR, "%s: setsockopt(%s): %s", __func__, optname, strerror(errno));
1508a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colitti  }
1518a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colitti
1528a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colitti  return ret;
1538a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colitti}
1548a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colitti
1558a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colitti/* function: add_anycast_address
1568a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colitti * adds an anycast IPv6 address to an interface, returns 0 on success and <0 on failure
1578a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colitti * sock      - the socket to add the address to
1588a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colitti * addr      - the IP address to add
1598a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colitti * ifname    - name of interface to add the address to
1608a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colitti */
1618a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colittiint add_anycast_address(int sock, struct in6_addr *addr, const char *ifname) {
1628a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colitti  int ifindex, s, ret;
1638a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colitti
1648a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colitti  ifindex = if_nametoindex(ifname);
1658a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colitti  if (!ifindex) {
1668a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colitti    logmsg(ANDROID_LOG_ERROR, "%s: unknown ifindex for interface %s", __func__, ifname);
1678a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colitti    return -ENODEV;
1688a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colitti  }
1698a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colitti
1708a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colitti  return do_anycast_setsockopt(sock, IPV6_JOIN_ANYCAST, addr, ifindex);
1718a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colitti}
1728a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colitti
1738a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colitti/* function: del_anycast_address
1748a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colitti * removes an anycast IPv6 address from the system, returns 0 on success and <0 on failure
1758a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colitti * sock      - the socket to remove from, must have had the address added via add_anycast_address
1768a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colitti * addr      - the IP address to remove
1778a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colitti */
1788a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colittiint del_anycast_address(int sock, struct in6_addr *addr) {
1798a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colitti  return do_anycast_setsockopt(sock, IPV6_LEAVE_ANYCAST, addr, 0);
1808a41a5d140b3cf56a54bdeef234e89ee12cba0dcLorenzo Colitti}
181