#endif
#endif
+/* If IPv6 is supported, define IN6_IS_ADDR_V4MAPPED() if missing. */
+#if defined(IPV6_TCLASS) && !defined(IN6_IS_ADDR_V4MAPPED)
+#define IN6_IS_ADDR_V4MAPPED(a) \
+((((const uint32_t *) (a))[0] == 0) \
+&& (((const uint32_t *) (a))[1] == 0) \
+&& (((const uint32_t *) (a))[2] == htonl (0xffff)))
+#endif
+
#if defined(__dietlibc__)
#include <strings.h>
#endif
return 1;
}
+/* Sets the TOS header in IPv4 and the traffic class header in IPv6 packets
+ * (as per RFC3260 #4 and BCP37 #4.2 and #5.2).
+ */
+static inline void inet_set_tos(int fd, struct sockaddr_storage from, int tos)
+{
+#ifdef IP_TOS
+ if (from.ss_family == AF_INET)
+ setsockopt(fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos));
+#endif
+#ifdef IPV6_TCLASS
+ if (from.ss_family == AF_INET6) {
+ if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&from)->sin6_addr))
+ /* v4-mapped addresses need IP_TOS */
+ setsockopt(fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos));
+ else
+ setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &tos, sizeof(tos));
+ }
+#endif
+}
+
/* Executes the http-request rules <rules> for session <s>, proxy <px> and
* transaction <txn>. Returns the first rule that prevents further processing
* of the request (auth, deny, ...) or NULL if it executed all rules or stopped
break;
case HTTP_REQ_ACT_SET_TOS:
-#ifdef IP_TOS
- if (s->req->prod->conn->addr.from.ss_family == AF_INET)
- setsockopt(s->req->prod->conn->t.sock.fd, IPPROTO_IP, IP_TOS, &rule->arg.tos, sizeof(rule->arg.tos));
-#endif
+ inet_set_tos(s->req->prod->conn->t.sock.fd, s->req->prod->conn->addr.from, rule->arg.tos);
break;
case HTTP_REQ_ACT_SET_MARK:
break;
case HTTP_RES_ACT_SET_TOS:
-#ifdef IP_TOS
- if (s->req->prod->conn->addr.from.ss_family == AF_INET)
- setsockopt(s->req->prod->conn->t.sock.fd, IPPROTO_IP, IP_TOS, &rule->arg.tos, sizeof(rule->arg.tos));
-#endif
+ inet_set_tos(s->req->prod->conn->t.sock.fd, s->req->prod->conn->addr.from, rule->arg.tos);
break;
case HTTP_RES_ACT_SET_MARK: