Mark the raw socket used by clatd.

This is required to use clatd on a non-default network.

(cherry picked from commit 10c1adce5e85b429bf45bf7f0208c6c37245fbfb)

Bug: 15340961
Change-Id: I779c83644727227a109bfeec1565364336b5ac2b
diff --git a/clatd.c b/clatd.c
index 001c4cb..0ee3831 100644
--- a/clatd.c
+++ b/clatd.c
@@ -178,7 +178,7 @@
     // 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.
+        // We don't log an error here because configure_packet_socket has already done so.
         exit(1);
     }
   }
@@ -244,10 +244,12 @@
   }
 }
 
-/* function: open_socket
- * opens raw and packet sockets
+/* function: open_sockets
+ * opens a packet socket to receive IPv6 packets and a raw socket to send them
+ * tunnel - tun device data
+ * mark - the socket mark to use for the sending raw socket
  */
-void open_sockets(struct tun_data *tunnel) {
+void open_sockets(struct tun_data *tunnel, uint32_t mark) {
   int rawsock = socket(AF_INET6, SOCK_RAW, IPPROTO_RAW);
   if (rawsock < 0) {
     logmsg(ANDROID_LOG_FATAL, "raw socket failed: %s", strerror(errno));
@@ -258,6 +260,9 @@
   if (setsockopt(rawsock, SOL_IPV6, IPV6_CHECKSUM, &off, sizeof(off)) < 0) {
     logmsg(ANDROID_LOG_WARN, "could not disable checksum on raw socket: %s", strerror(errno));
   }
+  if (mark != MARK_UNSET && setsockopt(rawsock, SOL_SOCKET, SO_MARK, &mark, sizeof(mark)) < 0) {
+    logmsg(ANDROID_LOG_ERROR, "could not set mark on raw socket: %s", strerror(errno));
+  }
 
   tunnel->write_fd6 = rawsock;
 
@@ -412,6 +417,18 @@
   printf("-i [uplink interface]\n");
   printf("-p [plat prefix]\n");
   printf("-n [NetId]\n");
+  printf("-m [socket mark]\n");
+}
+
+/* function: parse_unsigned
+ * parses a string as a decimal/hex/octal unsigned integer
+ * str - the string to parse
+ * out - the unsigned integer to write to, gets clobbered on failure
+ */
+int parse_unsigned(const char *str, unsigned *out) {
+    char *end_ptr;
+    *out = strtoul(str, &end_ptr, 0);
+    return *str && !*end_ptr;
 }
 
 /* function: main
@@ -420,12 +437,13 @@
 int main(int argc, char **argv) {
   struct tun_data tunnel;
   int opt;
-  char *uplink_interface = NULL, *plat_prefix = NULL, *net_id_str = NULL;
+  char *uplink_interface = NULL, *plat_prefix = NULL, *net_id_str = NULL, *mark_str = NULL;
   unsigned net_id = NETID_UNSET;
+  uint32_t mark = MARK_UNSET;
 
   strcpy(tunnel.device4, DEVICENAME4);
 
-  while((opt = getopt(argc, argv, "i:p:n:h")) != -1) {
+  while((opt = getopt(argc, argv, "i:p:n:m:h")) != -1) {
     switch(opt) {
       case 'i':
         uplink_interface = optarg;
@@ -436,6 +454,9 @@
       case 'n':
         net_id_str = optarg;
         break;
+      case 'm':
+        mark_str = optarg;
+        break;
       case 'h':
       default:
         print_help();
@@ -446,18 +467,21 @@
 
   if(uplink_interface == NULL) {
     logmsg(ANDROID_LOG_FATAL, "clatd called without an interface");
-    printf("I need an interface\n");
     exit(1);
   }
-  if (net_id_str != NULL) {
-    char *end_ptr;
-    net_id = strtoul(net_id_str, &end_ptr, 0);
-    if (*net_id_str == 0 || *end_ptr != 0) {
-      logmsg(ANDROID_LOG_FATAL, "clatd called with invalid NetID %s", net_id_str);
-      exit(1);
-    }
+
+  if (net_id_str != NULL && !parse_unsigned(net_id_str, &net_id)) {
+    logmsg(ANDROID_LOG_FATAL, "invalid NetID %s", net_id_str);
+    exit(1);
   }
-  logmsg(ANDROID_LOG_INFO, "Starting clat version %s on %s", CLATD_VERSION, uplink_interface);
+
+  if (mark_str != NULL && !parse_unsigned(mark_str, &mark)) {
+    logmsg(ANDROID_LOG_FATAL, "invalid mark %s", mark_str);
+    exit(1);
+  }
+
+  logmsg(ANDROID_LOG_INFO, "Starting clat version %s on %s netid=%s mark=%s", CLATD_VERSION,
+         uplink_interface, net_id_str, mark_str);
 
   // open the tunnel device and our raw sockets before dropping privs
   tunnel.fd4 = tun_open();
@@ -466,7 +490,7 @@
     exit(1);
   }
 
-  open_sockets(&tunnel);
+  open_sockets(&tunnel, mark);
 
   // run under a regular user
   drop_root();