]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
Set DSCP values when sending IP packets in socket-default
authorMartin Willi <martin@revosec.ch>
Wed, 6 Feb 2013 12:17:55 +0000 (13:17 +0100)
committerMartin Willi <martin@revosec.ch>
Wed, 6 Feb 2013 14:20:32 +0000 (15:20 +0100)
src/libcharon/plugins/socket_default/socket_default_socket.c

index 942dafc2e466e2689e0e72f342ccaf09d2f40547..c0b744a6860b2e54a94ba3d6f6f201cd6acb5284 100644 (file)
@@ -55,6 +55,9 @@
 #ifndef SOL_IPV6
 #define SOL_IPV6 IPPROTO_IPV6
 #endif
+#ifndef IPV6_TCLASS
+#define IPV6_TCLASS 67
+#endif
 
 /* IPV6_RECVPKTINFO is defined in RFC 3542 which obsoletes RFC 2292 that
  * previously defined IPV6_PKTINFO */
@@ -112,6 +115,26 @@ struct private_socket_default_socket_t {
         */
        int ipv6_natt;
 
+       /**
+        * DSCP value set on IPv4 socket
+        */
+       u_int8_t dscp4;
+
+       /**
+        * DSCP value set on IPv4 socket for NAT-T (4500 or natt)
+        */
+       u_int8_t dscp4_natt;
+
+       /**
+        * DSCP value set on IPv6 socket (500 or port)
+        */
+       u_int8_t dscp6;
+
+       /**
+        * DSCP value set on IPv6 socket for NAT-T (4500 or natt)
+        */
+       u_int8_t dscp6_natt;
+
        /**
         * Maximum packet size to receive
         */
@@ -310,6 +333,7 @@ METHOD(socket_t, sender, status_t,
        struct msghdr msg;
        struct cmsghdr *cmsg;
        struct iovec iov;
+       u_int8_t *dscp;
 
        src = packet->get_source(packet);
        dst = packet->get_destination(packet);
@@ -326,9 +350,11 @@ METHOD(socket_t, sender, status_t,
                {
                        case AF_INET:
                                skt = this->ipv4;
+                               dscp = &this->dscp4;
                                break;
                        case AF_INET6:
                                skt = this->ipv6;
+                               dscp = &this->dscp6;
                                break;
                        default:
                                return FAILED;
@@ -340,9 +366,11 @@ METHOD(socket_t, sender, status_t,
                {
                        case AF_INET:
                                skt = this->ipv4_natt;
+                               dscp = &this->dscp4_natt;
                                break;
                        case AF_INET6:
                                skt = this->ipv6_natt;
+                               dscp = &this->dscp6_natt;
                                break;
                        default:
                                return FAILED;
@@ -354,6 +382,43 @@ METHOD(socket_t, sender, status_t,
                return FAILED;
        }
 
+       /* setting DSCP values per-packet in a cmsg seems not to be supported
+        * on Linux. We instead setsockopt() before sending it, this should be
+        * safe as only a single thread calls send(). */
+       if (*dscp != packet->get_dscp(packet))
+       {
+               if (family == AF_INET)
+               {
+                       u_int8_t ds4;
+
+                       ds4 = packet->get_dscp(packet) << 2;
+                       if (setsockopt(skt, SOL_IP, IP_TOS, &ds4, sizeof(ds4)) == 0)
+                       {
+                               *dscp = packet->get_dscp(packet);
+                       }
+                       else
+                       {
+                               DBG1(DBG_NET, "unable to set IP_TOS on socket: %s",
+                                        strerror(errno));
+                       }
+               }
+               else
+               {
+                       u_int ds6;
+
+                       ds6 = packet->get_dscp(packet) << 2;
+                       if (setsockopt(skt, SOL_IPV6, IPV6_TCLASS, &ds6, sizeof(ds6)) == 0)
+                       {
+                               *dscp = packet->get_dscp(packet);
+                       }
+                       else
+                       {
+                               DBG1(DBG_NET, "unable to set IPV6_TCLASS on socket: %s",
+                                        strerror(errno));
+                       }
+               }
+       }
+
        memset(&msg, 0, sizeof(struct msghdr));
        msg.msg_name = dst->get_sockaddr(dst);;
        msg.msg_namelen = *dst->get_sockaddr_len(dst);
@@ -640,4 +705,3 @@ socket_default_socket_t *socket_default_socket_create()
 
        return &this->public;
 }
-