diff options
author | Lorenzo Colitti <lorenzo@google.com> | 2014-06-13 03:04:12 +0000 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2014-06-13 03:04:12 +0000 |
commit | fa6e9d325622d7a507b2e9d19e2e145647295ee6 (patch) | |
tree | 2a3dfdecd85d5c0ac00c37a35208e1565f9c84c5 | |
parent | ffe528a969017b7d1687528ddf580395e54fb99d (diff) | |
parent | f08c5aa666d170c17abb784081897ea169c1b67f (diff) | |
download | platform_external_android-clat-fa6e9d325622d7a507b2e9d19e2e145647295ee6.tar.gz platform_external_android-clat-fa6e9d325622d7a507b2e9d19e2e145647295ee6.tar.bz2 platform_external_android-clat-fa6e9d325622d7a507b2e9d19e2e145647295ee6.zip |
am f08c5aa6: Use a packet socket to receive packets.
* commit 'f08c5aa666d170c17abb784081897ea169c1b67f':
Use a packet socket to receive packets.
-rw-r--r-- | Android.mk | 2 | ||||
-rw-r--r-- | clatd.c | 205 | ||||
-rw-r--r-- | clatd.h | 4 | ||||
-rw-r--r-- | config.c | 1 | ||||
-rw-r--r-- | dump.c | 6 | ||||
-rw-r--r-- | getroute.c | 144 | ||||
-rw-r--r-- | getroute.h | 35 | ||||
-rw-r--r-- | setroute.c | 141 | ||||
-rw-r--r-- | setroute.h | 27 |
9 files changed, 102 insertions, 463 deletions
@@ -1,7 +1,7 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) -LOCAL_SRC_FILES:=clatd.c dump.c checksum.c translate.c icmp.c ipv4.c ipv6.c config.c dns64.c logging.c getaddr.c getroute.c netlink_callbacks.c netlink_msg.c setif.c setroute.c mtu.c +LOCAL_SRC_FILES:=clatd.c dump.c checksum.c translate.c icmp.c ipv4.c ipv6.c config.c dns64.c logging.c getaddr.c netlink_callbacks.c netlink_msg.c setif.c mtu.c LOCAL_CFLAGS := -Wall -Werror -Wunused-parameter LOCAL_C_INCLUDES := external/libnl/include bionic/libc/dns/include @@ -32,9 +32,12 @@ #include <sys/capability.h> #include <sys/uio.h> #include <linux/prctl.h> +#include <linux/filter.h> #include <linux/if.h> #include <linux/if_tun.h> #include <linux/if_ether.h> +#include <linux/if_packet.h> +#include <net/if.h> #include <private/android_filesystem_config.h> @@ -44,31 +47,17 @@ #include "logging.h" #include "resolv_netid.h" #include "setif.h" -#include "setroute.h" #include "mtu.h" #include "getaddr.h" #include "dump.h" -#define DEVICENAME6 "clat" #define DEVICENAME4 "clat4" /* 40 bytes IPv6 header - 20 bytes IPv4 header + 8 bytes fragment header */ #define MTU_DELTA 28 -int forwarding_fd = -1; volatile sig_atomic_t running = 1; -/* function: set_forwarding - * enables/disables ipv6 forwarding - */ -void set_forwarding(int fd, const char *setting) { - /* we have to forward packets from the WAN to the tun interface */ - if(write(fd, setting, strlen(setting)) < 0) { - logmsg(ANDROID_LOG_FATAL,"set_forwarding(%s) failed: %s", setting, strerror(errno)); - exit(1); - } -} - /* function: stop_loop * signal handler: stop the event loop */ @@ -114,34 +103,51 @@ int tun_alloc(char *dev, int fd) { return 0; } -/* function: deconfigure_tun_ipv6 - * removes the ipv6 route - * tunnel - tun device data - */ -void deconfigure_tun_ipv6(const struct tun_data *tunnel) { - int status; - - status = if_route(tunnel->device6, AF_INET6, &Global_Clatd_Config.ipv6_local_subnet, - 128, NULL, 1, 0, ROUTE_DELETE); - if(status < 0) { - logmsg(ANDROID_LOG_WARN,"deconfigure_tun_ipv6/if_route(6) failed: %s",strerror(-status)); - } -} - -/* function: configure_tun_ipv6 - * configures the ipv6 route - * note: routes a /128 out of the (assumed routed to us) /64 to the CLAT interface - * tunnel - tun device data +/* function: configure_packet_socket + * Binds the packet socket and attaches the receive filter to it. + * sock - the socket to configure */ -void configure_tun_ipv6(const struct tun_data *tunnel) { - int status; - - status = if_route(tunnel->device6, AF_INET6, &Global_Clatd_Config.ipv6_local_subnet, - 128, NULL, 1, 0, ROUTE_CREATE); - if(status < 0) { - logmsg(ANDROID_LOG_FATAL,"configure_tun_ipv6/if_route(6) failed: %s",strerror(-status)); - exit(1); - } +int configure_packet_socket(int sock) { + struct sockaddr_ll sll = { + .sll_family = AF_PACKET, + .sll_protocol = htons(ETH_P_IPV6), + .sll_ifindex = if_nametoindex((char *) &Global_Clatd_Config.default_pdp_interface), + .sll_pkttype = PACKET_OTHERHOST, // The 464xlat IPv6 address is not assigned to the kernel. + }; + if (bind(sock, (struct sockaddr *) &sll, sizeof(sll))) { + logmsg(ANDROID_LOG_FATAL, "binding packet socket: %s", strerror(errno)); + return 0; + } + + uint32_t *ipv6 = Global_Clatd_Config.ipv6_local_subnet.s6_addr32; + struct sock_filter filter_code[] = { + // Load the first four bytes of the IPv6 destination address (starts 24 bytes in). + // Compare it against the first four bytes of our IPv6 address, in host byte order (BPF loads + // are always in host byte order). If it matches, continue with next instruction (JMP 0). If it + // doesn't match, jump ahead to statement that returns 0 (ignore packet). Repeat for the other + // three words of the IPv6 address, and if they all match, return PACKETLEN (accept packet). + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, 24), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htonl(ipv6[0]), 0, 7), + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, 28), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htonl(ipv6[1]), 0, 5), + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, 32), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htonl(ipv6[2]), 0, 3), + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, 36), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htonl(ipv6[3]), 0, 1), + BPF_STMT(BPF_RET | BPF_K, PACKETLEN), + BPF_STMT(BPF_RET | BPF_K, 0) + }; + struct sock_fprog filter = { + sizeof(filter_code) / sizeof(filter_code[0]), + filter_code + }; + + if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter))) { + logmsg(ANDROID_LOG_FATAL, "attach packet filter failed: %s", strerror(errno)); + return 0; + } + + return 1; } /* function: interface_poll @@ -153,7 +159,8 @@ void interface_poll(const struct tun_data *tunnel) { interface_ip = getinterface_ip(Global_Clatd_Config.default_pdp_interface, AF_INET6); if(!interface_ip) { - logmsg(ANDROID_LOG_WARN,"unable to find an ipv6 ip on interface %s",Global_Clatd_Config.default_pdp_interface); + logmsg(ANDROID_LOG_WARN,"unable to find an ipv6 ip on interface %s", + Global_Clatd_Config.default_pdp_interface); return; } @@ -165,12 +172,15 @@ void interface_poll(const struct tun_data *tunnel) { inet_ntop(AF_INET6, &interface_ip->ip6, to_addr, sizeof(to_addr)); logmsg(ANDROID_LOG_WARN, "clat subnet changed from %s to %s", from_addr, to_addr); - // remove old route - deconfigure_tun_ipv6(tunnel); - - // add new route, start translating packets to the new prefix + // Start translating packets to the new prefix. memcpy(&Global_Clatd_Config.ipv6_local_subnet, &interface_ip->ip6, sizeof(struct in6_addr)); - configure_tun_ipv6(tunnel); + + // Update our packet socket filter to reflect the new 464xlat IP address. + if (!configure_packet_socket(tunnel->read_fd6)) { + // Things aren't going to work. Bail out and hope we have better luck next time. + // We don't log an error here because attach_filter has already done so. + exit(1); + } } free(interface_ip); @@ -192,24 +202,10 @@ void configure_tun_ip(const struct tun_data *tunnel) { exit(1); } - status = add_address(tunnel->device6, AF_INET6, &Global_Clatd_Config.ipv6_local_address, - 64, NULL); - if(status < 0) { - logmsg(ANDROID_LOG_FATAL,"configure_tun_ip/if_address(6) failed: %s",strerror(-status)); - exit(1); - } - - if((status = if_up(tunnel->device6, Global_Clatd_Config.mtu)) < 0) { - logmsg(ANDROID_LOG_FATAL,"configure_tun_ip/if_up(6) failed: %s",strerror(-status)); - exit(1); - } - if((status = if_up(tunnel->device4, Global_Clatd_Config.ipv4mtu)) < 0) { logmsg(ANDROID_LOG_FATAL,"configure_tun_ip/if_up(4) failed: %s",strerror(-status)); exit(1); } - - configure_tun_ipv6(tunnel); } /* function: drop_root @@ -248,10 +244,10 @@ void drop_root() { } } -/* function: open_raw_socket - * opens the raw socket for sending IPv6 packets +/* function: open_socket + * opens raw and packet sockets */ -void open_raw_socket(struct tun_data *tunnel) { +void open_sockets(struct tun_data *tunnel) { int rawsock = socket(AF_INET6, SOCK_RAW, IPPROTO_RAW); if (rawsock < 0) { logmsg(ANDROID_LOG_FATAL, "raw socket failed: %s", strerror(errno)); @@ -264,6 +260,14 @@ void open_raw_socket(struct tun_data *tunnel) { } tunnel->write_fd6 = rawsock; + + int packetsock = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_IPV6)); + if (packetsock < 0) { + logmsg(ANDROID_LOG_FATAL, "packet socket failed: %s", strerror(errno)); + exit(1); + } + + tunnel->read_fd6 = packetsock; } /* function: configure_interface @@ -300,12 +304,6 @@ void configure_interface(const char *uplink_interface, const char *plat_prefix, logmsg(ANDROID_LOG_WARN,"ipv4mtu now set to = %d",Global_Clatd_Config.ipv4mtu); } - error = tun_alloc(tunnel->device6, tunnel->read_fd6); - if(error < 0) { - logmsg(ANDROID_LOG_FATAL,"tun_alloc failed: %s",strerror(errno)); - exit(1); - } - error = tun_alloc(tunnel->device4, tunnel->fd4); if(error < 0) { logmsg(ANDROID_LOG_FATAL,"tun_alloc/4 failed: %s",strerror(errno)); @@ -322,13 +320,10 @@ void configure_interface(const char *uplink_interface, const char *plat_prefix, */ void read_packet(int active_fd, const struct tun_data *tunnel) { ssize_t readlen; - uint8_t packet[PACKETLEN]; - - // In case something ignores the packet length. - // TODO: remove it. - memset(packet, 0, PACKETLEN); + uint8_t buf[PACKETLEN], *packet; + int fd; - readlen = read(active_fd,packet,PACKETLEN); + readlen = read(active_fd, buf, PACKETLEN); if(readlen < 0) { logmsg(ANDROID_LOG_WARN,"read_packet/read error: %s", strerror(errno)); @@ -336,32 +331,37 @@ void read_packet(int active_fd, const struct tun_data *tunnel) { } else if(readlen == 0) { logmsg(ANDROID_LOG_WARN,"read_packet/tun interface removed"); running = 0; - } else { + return; + } + + if (active_fd == tunnel->fd4) { ssize_t header_size = sizeof(struct tun_pi); - if(readlen < header_size) { + if (readlen < header_size) { logmsg(ANDROID_LOG_WARN,"read_packet/short read: got %ld bytes", readlen); return; } - struct tun_pi *tun_header = (struct tun_pi *) packet; - if(tun_header->flags != 0) { - logmsg(ANDROID_LOG_WARN, "%s: unexpected flags = %d", __func__, tun_header->flags); - } - - int fd; + struct tun_pi *tun_header = (struct tun_pi *) buf; uint16_t proto = ntohs(tun_header->proto); - if (proto == ETH_P_IP) { - fd = tunnel->write_fd6; - } else if (proto == ETH_P_IPV6) { - fd = tunnel->fd4; - } else { + if (proto != ETH_P_IP) { logmsg(ANDROID_LOG_WARN, "%s: unknown packet type = 0x%x", __func__, proto); return; } - translate_packet(fd, (proto == ETH_P_IP), packet + header_size, readlen - header_size); + if(tun_header->flags != 0) { + logmsg(ANDROID_LOG_WARN, "%s: unexpected flags = %d", __func__, tun_header->flags); + } + + fd = tunnel->write_fd6; + packet = buf + header_size; + readlen -= header_size; + } else { + fd = tunnel->fd4; + packet = buf; } + + translate_packet(fd, (fd == tunnel->write_fd6), packet, readlen); } /* function: event_loop @@ -423,7 +423,6 @@ int main(int argc, char **argv) { char *uplink_interface = NULL, *plat_prefix = NULL, *net_id_str = NULL; unsigned net_id = NETID_UNSET; - strcpy(tunnel.device6, DEVICENAME6); strcpy(tunnel.device4, DEVICENAME4); while((opt = getopt(argc, argv, "i:p:n:h")) != -1) { @@ -460,28 +459,14 @@ int main(int argc, char **argv) { } logmsg(ANDROID_LOG_INFO, "Starting clat version %s on %s", CLATD_VERSION, uplink_interface); - // open the tunnel device before dropping privs - tunnel.read_fd6 = tun_open(); - if(tunnel.read_fd6 < 0) { - logmsg(ANDROID_LOG_FATAL, "tun_open6 failed: %s", strerror(errno)); - exit(1); - } - + // open the tunnel device and our raw sockets before dropping privs tunnel.fd4 = tun_open(); if(tunnel.fd4 < 0) { logmsg(ANDROID_LOG_FATAL, "tun_open4 failed: %s", strerror(errno)); exit(1); } - // open the forwarding configuration before dropping privs - forwarding_fd = open("/proc/sys/net/ipv6/conf/all/forwarding", O_RDWR); - if(forwarding_fd < 0) { - logmsg(ANDROID_LOG_FATAL,"open /proc/sys/net/ipv6/conf/all/forwarding failed: %s", - strerror(errno)); - exit(1); - } - - open_raw_socket(&tunnel); + open_sockets(&tunnel); // run under a regular user drop_root(); @@ -492,7 +477,10 @@ int main(int argc, char **argv) { configure_interface(uplink_interface, plat_prefix, &tunnel, net_id); - set_forwarding(forwarding_fd,"1\n"); + if (!configure_packet_socket(tunnel.read_fd6)) { + // We've already logged an error. + exit(1); + } // Loop until someone sends us a signal or brings down the tun interface. if(signal(SIGTERM, stop_loop) == SIG_ERR) { @@ -501,7 +489,6 @@ int main(int argc, char **argv) { } event_loop(&tunnel); - set_forwarding(forwarding_fd,"0\n"); logmsg(ANDROID_LOG_INFO,"Shutting down clat on %s", uplink_interface); return 0; @@ -23,7 +23,7 @@ #define MAXMTU 1500 #define PACKETLEN (MAXMTU+sizeof(struct tun_pi)) -#define CLATD_VERSION "1.2" +#define CLATD_VERSION "1.3" // how frequently (in seconds) to poll for an address change while traffic is passing #define INTERFACE_POLL_FREQUENCY 30 @@ -32,7 +32,7 @@ #define NO_TRAFFIC_INTERFACE_POLL_FREQUENCY 90 struct tun_data { - char device6[IFNAMSIZ], device4[IFNAMSIZ]; + char device4[IFNAMSIZ]; int read_fd6, write_fd6, fd4; }; @@ -31,7 +31,6 @@ #include "logging.h" #include "getaddr.h" #include "clatd.h" -#include "setroute.h" struct clat_config Global_Clatd_Config; @@ -162,7 +162,7 @@ void dump_udp6(const struct udphdr *udp, const struct ip6_hdr *ip6, } /* print tcp header */ -void dump_tcp_generic(const struct tcphdr *tcp, const char *options, size_t options_size, uint32_t temp_checksum, const char *payload, size_t payload_size) { +void dump_tcp_generic(const struct tcphdr *tcp, const uint8_t *options, size_t options_size, uint32_t temp_checksum, const uint8_t *payload, size_t payload_size) { uint16_t my_checksum; temp_checksum = ip_checksum_add(temp_checksum, tcp, sizeof(struct tcphdr)); @@ -205,7 +205,7 @@ void dump_tcp_generic(const struct tcphdr *tcp, const char *options, size_t opti /* print ipv4/tcp header */ void dump_tcp(const struct tcphdr *tcp, const struct iphdr *ip, const uint8_t *payload, size_t payload_size, - const char *options, size_t options_size) { + const uint8_t *options, size_t options_size) { uint32_t temp_checksum; temp_checksum = ipv4_pseudo_header_checksum(ip, sizeof(*tcp) + options_size + payload_size); @@ -215,7 +215,7 @@ void dump_tcp(const struct tcphdr *tcp, const struct iphdr *ip, /* print ipv6/tcp header */ void dump_tcp6(const struct tcphdr *tcp, const struct ip6_hdr *ip6, const uint8_t *payload, size_t payload_size, - const char *options, size_t options_size) { + const uint8_t *options, size_t options_size) { uint32_t temp_checksum; temp_checksum = ipv6_pseudo_header_checksum(ip6, sizeof(*tcp) + options_size + payload_size, IPPROTO_TCP); diff --git a/getroute.c b/getroute.c deleted file mode 100644 index a615a4f..0000000 --- a/getroute.c +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright 2012 Daniel Drown - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * getroute.c - get an ip route - */ -#include <string.h> -#include <errno.h> - -#include <sys/socket.h> -#include <linux/netlink.h> -#include <linux/rtnetlink.h> -#include <arpa/inet.h> - -#include <netlink/handlers.h> -#include <netlink/msg.h> - -#include "getroute.h" -#include "netlink_callbacks.h" -#include "netlink_msg.h" - -/* function: get_default_route_cb - * finds the default route with the request family and out interface and saves the gateway - * msg - netlink message - * data - (struct default_route_data) requested filters and response storage - */ -static int get_default_route_cb(struct nl_msg *msg, void *data) { - struct rtmsg *rt_p; - struct rtattr *rta_p; - int rta_len; - struct default_route_data *default_route = data; - union anyip *this_gateway = NULL; - ssize_t this_gateway_size; - int this_interface_id = -1; - - if(default_route->reply_found_route) { // we already found our route - return NL_OK; - } - - rt_p = (struct rtmsg *)nlmsg_data(nlmsg_hdr(msg)); - if(rt_p->rtm_dst_len != 0) { // not a default route - return NL_OK; - } - if((rt_p->rtm_family != default_route->request_family) || (rt_p->rtm_table != RT_TABLE_MAIN)) { // not a route we care about - return NL_OK; - } - - rta_p = (struct rtattr *)RTM_RTA(rt_p); - rta_len = RTM_PAYLOAD(nlmsg_hdr(msg)); - for(; RTA_OK(rta_p, rta_len); rta_p = RTA_NEXT(rta_p, rta_len)) { - switch(rta_p->rta_type) { - case RTA_GATEWAY: - this_gateway = RTA_DATA(rta_p); - this_gateway_size = RTA_PAYLOAD(rta_p); - break; - case RTA_OIF: - this_interface_id = *(int *)RTA_DATA(rta_p); - break; - default: - break; - } - } - - if(this_interface_id == default_route->request_interface_id) { - default_route->reply_found_route = 1; - if(this_gateway != NULL) { - memcpy(&default_route->reply_gateway, this_gateway, this_gateway_size); - default_route->reply_has_gateway = 1; - } else { - default_route->reply_has_gateway = 0; - } - } - return NL_OK; -} - -/* function: error_handler - * error callback for get_default_route - * nla - where the message came from - * err - netlink message - * arg - (int *) storage for the error number - */ -static int error_handler(__attribute__((unused)) struct sockaddr_nl *nla, - struct nlmsgerr *err, void *arg) { - int *retval = arg; - if(err->error < 0) { // error_handler called even on no error (NLMSG_ERROR reply type used) - *retval = err->error; - } - return NL_OK; -} - -/* function: get_default_route - * finds the first default route with the given family and interface, returns the gateway (if it exists) in the struct - * default_route - requested family and interface, and response storage - */ -int get_default_route(struct default_route_data *default_route) { - struct rtmsg msg; - struct nl_cb *callbacks = NULL; - struct nl_msg *nlmsg = NULL; - int retval = 0; - - default_route->reply_has_gateway = 0; - default_route->reply_found_route = 0; - - memset(&msg,'\0',sizeof(msg)); - msg.rtm_family = default_route->request_family; - msg.rtm_table = RT_TABLE_MAIN; - msg.rtm_protocol = RTPROT_KERNEL; - msg.rtm_scope = RT_SCOPE_UNIVERSE; - - callbacks = nl_cb_alloc(NL_CB_DEFAULT); - if(!callbacks) { - retval = -ENOMEM; - goto cleanup; - } - // get_default_route_cb sets the response fields in default_route - nl_cb_set(callbacks, NL_CB_VALID, NL_CB_CUSTOM, get_default_route_cb, default_route); - nl_cb_err(callbacks, NL_CB_CUSTOM, error_handler, &retval); - - nlmsg = nlmsg_alloc_rtmsg(RTM_GETROUTE, NLM_F_REQUEST | NLM_F_ROOT, &msg); - if(!nlmsg) { - retval = -ENOMEM; - goto cleanup; - } - send_netlink_msg(nlmsg, callbacks); - -cleanup: - if(callbacks) - nl_cb_put(callbacks); - if(nlmsg) - nlmsg_free(nlmsg); - - return retval; -} diff --git a/getroute.h b/getroute.h deleted file mode 100644 index e7b8670..0000000 --- a/getroute.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2012 Daniel Drown - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * getroute.h - get an ip route - */ -#ifndef __GETROUTE_H__ -#define __GETROUTE_H__ - -// for union anyip -#include "getaddr.h" - -struct default_route_data { - int request_interface_id; - int request_family; - - union anyip reply_gateway; - int reply_has_gateway; - int reply_found_route; -}; - -int get_default_route(struct default_route_data *default_route); - -#endif diff --git a/setroute.c b/setroute.c deleted file mode 100644 index cffee9f..0000000 --- a/setroute.c +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright 2012 Daniel Drown <dan-android@drown.org> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * setroute.c - network route configuration - */ -#include <errno.h> -#include <netinet/in.h> -#include <net/if.h> - -#include <linux/netlink.h> -#include <linux/rtnetlink.h> -#include <netlink/handlers.h> -#include <netlink/msg.h> - -#include "netlink_msg.h" -#include "setroute.h" -#include "logging.h" -#include "getroute.h" - -/* function: if_route - * create/replace/delete a route - * ifname - name of the outbound interface - * family - AF_INET or AF_INET6 - * destination - pointer to a struct in_addr or in6_addr for the destination network - * prefixlen - bitlength of the network address (example: 24 for AF_INET's 255.255.255.0) - * gateway - pointer to a struct in_addr or in6_addr for the gateway to use or NULL for an interface route - * metric - route metric (lower is better) - * mtu - route-specific mtu or 0 for the interface mtu - * change_type - ROUTE_DELETE, ROUTE_REPLACE, or ROUTE_CREATE - */ -int if_route(const char *ifname, int family, const void *destination, int prefixlen, const void *gateway, int metric, int mtu, int change_type) { - int retval; - struct nl_msg *msg = NULL; - struct rtmsg rt; - uint16_t type, flags = 0; - size_t addr_size; - uint32_t ifindex; - - addr_size = inet_family_size(family); - if(addr_size == 0) { - retval = -EAFNOSUPPORT; - goto cleanup; - } - - if (!(ifindex = if_nametoindex(ifname))) { - retval = -ENODEV; - goto cleanup; - } - - memset(&rt, 0, sizeof(rt)); - rt.rtm_family = family; - rt.rtm_table = RT_TABLE_MAIN; - rt.rtm_dst_len = prefixlen; - switch(change_type) { - case ROUTE_DELETE: - rt.rtm_scope = RT_SCOPE_NOWHERE; - type = RTM_DELROUTE; - break; - - case ROUTE_REPLACE: - flags = NLM_F_REPLACE; - case ROUTE_CREATE: - type = RTM_NEWROUTE; - flags |= NLM_F_CREATE; - if(gateway == NULL) { - rt.rtm_scope = RT_SCOPE_LINK; - } else { - rt.rtm_scope = RT_SCOPE_UNIVERSE; - } - rt.rtm_type = RTN_UNICAST; - //RTPROT_STATIC = from administrator's configuration - //RTPROT_BOOT = from an automatic process - rt.rtm_protocol = RTPROT_BOOT; - break; - - default: - retval = -EINVAL; - goto cleanup; - } - - flags |= NLM_F_REQUEST | NLM_F_ACK; - - msg = nlmsg_alloc_rtmsg(type, flags, &rt); - if(!msg) { - retval = -ENOMEM; - goto cleanup; - } - - if(nla_put(msg, RTA_DST, addr_size, destination) < 0) { - retval = -ENOMEM; - goto cleanup; - } - if(gateway != NULL) - if(nla_put(msg, RTA_GATEWAY, addr_size, gateway) < 0) { - retval = -ENOMEM; - goto cleanup; - } - if(nla_put(msg, RTA_OIF, 4, &ifindex) < 0) { - retval = -ENOMEM; - goto cleanup; - } - if(nla_put(msg, RTA_PRIORITY, 4, &metric) < 0) { - retval = -ENOMEM; - goto cleanup; - } - if(mtu > 0 && change_type != ROUTE_DELETE) { - // MTU is inside an RTA_METRICS nested message - struct nlattr *metrics = nla_nest_start(msg, RTA_METRICS); - if(metrics == NULL) { - retval = -ENOMEM; - goto cleanup; - } - - if(nla_put(msg, RTAX_MTU, 4, &mtu) < 0) { - retval = -ENOMEM; - goto cleanup; - } - - nla_nest_end(msg, metrics); - } - - retval = netlink_sendrecv(msg); - -cleanup: - if(msg) - nlmsg_free(msg); - - return retval; -} diff --git a/setroute.h b/setroute.h deleted file mode 100644 index 58f61cf..0000000 --- a/setroute.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2012 Daniel Drown <dan-android@drown.org> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * setroute.h - network route configuration - */ - -#ifndef __SETROUTE_H__ -#define __SETROUTE_H__ - -#define ROUTE_DELETE 0 -#define ROUTE_REPLACE 1 -#define ROUTE_CREATE 2 -int if_route(const char *ifname, int family, const void *destination, int cidr, const void *gateway, int metric, int mtu, int change_type); - -#endif |