DSCP: inbound via control = dscp/<value>
authorPhil Pennock <pdp@exim.org>
Sun, 3 Jun 2012 13:42:50 +0000 (09:42 -0400)
committerPhil Pennock <pdp@exim.org>
Sun, 3 Jun 2012 13:42:50 +0000 (09:42 -0400)
doc/doc-docbook/spec.xfpt
doc/doc-txt/ChangeLog
doc/doc-txt/NewStuff
src/src/acl.c
src/src/functions.h
src/src/ip.c

index 3c5f5bd..b8507f9 100644 (file)
@@ -22115,8 +22115,7 @@ details.
 
 .new
 .option dscp smtp string&!! unset
-.cindex "DCSP"
-.cindex "DiffServ"
+.cindex "DCSP" "outbound"
 This option causes the DSCP value associated with a socket to be set to one
 of a number of fixed strings or to numeric value.
 The &%-bI:dscp%& option may be used to ask Exim which names it knows of.
@@ -22125,7 +22124,7 @@ Common values include &`throughput`&, &`mincost`&, and on newer systems
 
 The outbound packets from Exim will be marked with this value in the header
 (for IPv4, the TOS field; for IPv6, the TCLASS field); there is no guarantee
-that these packets will have any effect, not be stripped by networking
+that these values will have any effect, not be stripped by networking
 equipment, or do much of anything without cooperation with your Network
 Engineer and those of all network operators between the source and destination.
 .wen
@@ -26811,6 +26810,25 @@ Notice that we put back the lower cased version afterwards, assuming that
 is what is wanted for subsequent tests.
 
 
+.new
+.vitem &*control&~=&~dscp/*&<&'value'&>
+.cindex "&ACL;" "setting DSCP value"
+.cindex "DSCP" "inbound"
+This option causes the DSCP value associated with the socket for the inbound
+connection to be adjusted to a given value, given as one of a number of fixed
+strings or to numeric value.
+The &%-bI:dscp%& option may be used to ask Exim which names it knows of.
+Common values include &`throughput`&, &`mincost`&, and on newer systems
+&`ef`&, &`af41`&, etc.  Numeric values may be in the range 0 to 0x3F.
+
+The outbound packets from Exim will be marked with this value in the header
+(for IPv4, the TOS field; for IPv6, the TCLASS field); there is no guarantee
+that these values will have any effect, not be stripped by networking
+equipment, or do much of anything without cooperation with your Network
+Engineer and those of all network operators between the source and destination.
+.wen
+
+
 .vitem &*control&~=&~debug/*&<&'options'&>
 .cindex "&ACL;" "enabling debug logging"
 .cindex "debugging" "enabling from an ACL"
index 1e8063b..3739345 100644 (file)
@@ -16,7 +16,7 @@ PP/04 First step towards DNSSEC, provide $sender_host_dnssec for
       $sender_host_name and config options to manage this, and basic check
       routines.
 
-PP/05 DSCP support for outbound connections.
+PP/05 DSCP support for outbound connections and control modifier for inbound.
 
 
 Exim version 4.80
index e33d285..7b0da68 100644 (file)
@@ -41,9 +41,13 @@ Version 4.81
 
  5. DSCP support for outbound connections: on a transport using the smtp driver,
     set "dscp = ef", for instance, to cause the connections to have the relevant
-    DSCP (IPv4 TOS or IPv6 TCLASS) value in the header.  Supported values depend
-    upon system libraries.  "exim -bI:dscp" to list the ones Exim knows of.
-    You can also set a raw number 0..0x3F.
+    DSCP (IPv4 TOS or IPv6 TCLASS) value in the header.
+
+    Similarly for inbound connections, there is a new control modifier, dscp,
+    so "warn control = dscp/ef" in the connect ACL, or after authentication.
+
+    Supported values depend upon system libraries.  "exim -bI:dscp" to list the
+    ones Exim knows of.  You can also set a raw number 0..0x3F.
 
 
 Version 4.80
index 5b5390d..505ccf9 100644 (file)
@@ -173,6 +173,7 @@ enum {
   #ifndef DISABLE_DKIM
   CONTROL_DKIM_VERIFY,
   #endif
+  CONTROL_DSCP,
   CONTROL_ERROR,
   CONTROL_CASEFUL_LOCAL_PART,
   CONTROL_CASELOWER_LOCAL_PART,
@@ -207,6 +208,7 @@ static uschar *controls[] = {
   #ifndef DISABLE_DKIM
   US"dkim_disable_verify",
   #endif
+  US"dscp",
   US"error",
   US"caseful_local_part",
   US"caselower_local_part",
@@ -524,6 +526,10 @@ static unsigned int control_forbids[] = {
     (1<<ACL_WHERE_NOTSMTP_START),
   #endif
 
+  (1<<ACL_WHERE_NOTSMTP)|
+    (1<<ACL_WHERE_NOTSMTP_START)|
+    (1<<ACL_WHERE_NOTQUIT),                        /* dscp */
+
   0,                                               /* error */
 
   (unsigned int)
@@ -604,6 +610,7 @@ static control_def controls_list[] = {
 #ifndef DISABLE_DKIM
   { US"dkim_disable_verify",     CONTROL_DKIM_VERIFY, FALSE },
 #endif
+  { US"dscp",                    CONTROL_DSCP, TRUE },
   { US"caseful_local_part",      CONTROL_CASEFUL_LOCAL_PART, FALSE },
   { US"caselower_local_part",    CONTROL_CASELOWER_LOCAL_PART, FALSE },
   { US"enforce_sync",            CONTROL_ENFORCE_SYNC, FALSE },
@@ -2847,6 +2854,46 @@ for (; cb != NULL; cb = cb->next)
       break;
       #endif
 
+      case CONTROL_DSCP:
+      if (*p == '/')
+        {
+        int fd, af, level, optname, value;
+        /* If we are acting on stdin, the setsockopt may fail if stdin is not
+        a socket; we can accept that, we'll just debug-log failures anyway. */
+        fd = fileno(smtp_in);
+        af = ip_get_address_family(fd);
+        if (af < 0)
+          {
+          HDEBUG(D_acl)
+            debug_printf("smtp input is probably not a socket [%s], not setting DSCP\n",
+                strerror(errno));
+          break;
+          }
+        if (dscp_lookup(p+1, af, &level, &optname, &value))
+          {
+          if (setsockopt(fd, level, optname, &value, sizeof(value)) < 0)
+            {
+            HDEBUG(D_acl) debug_printf("failed to set input DSCP[%s]: %s\n",
+                p+1, strerror(errno));
+            }
+          else
+            {
+            HDEBUG(D_acl) debug_printf("set input DSCP to \"%s\"\n", p+1);
+            }
+          }
+        else
+          {
+          *log_msgptr = string_sprintf("unrecognised DSCP value in \"control=%s\"", arg);
+          return ERROR;
+          }
+        }
+      else
+        {
+        *log_msgptr = string_sprintf("syntax error in \"control=%s\"", arg);
+        return ERROR;
+        }
+      break;
+
       case CONTROL_ERROR:
       return ERROR;
 
index 7fea6ff..3e78aa6 100644 (file)
@@ -155,6 +155,7 @@ extern int     host_scan_for_local_hosts(host_item *, host_item **, BOOL *);
 extern void    invert_address(uschar *, uschar *);
 extern int     ip_bind(int, int, uschar *, int);
 extern int     ip_connect(int, int, uschar *, int, int);
+extern int     ip_get_address_family(int);
 extern void    ip_keepalive(int, uschar *, BOOL);
 extern int     ip_recv(int, uschar *, int, int);
 extern int     ip_socket(int, int);
index 2be6824..11f0fd8 100644 (file)
@@ -362,6 +362,37 @@ return -1;
 
 
 /*************************************************
+*    Lookup address family of potential socket   *
+*************************************************/
+
+/* Given a file-descriptor, check to see if it's a socket and, if so,
+return the address family; detects IPv4 vs IPv6.  If not a socket then
+return -1.
+
+The value 0 is typically AF_UNSPEC, which should not be seen on a connected
+fd.  If the return is -1, the errno will be from getsockname(); probably
+ENOTSOCK or ECONNRESET.
+
+Arguments:     socket-or-not fd
+Returns:       address family or -1
+*/
+
+int
+ip_get_address_family(int fd)
+{
+struct sockaddr_storage ss;
+socklen_t sslen = sizeof(ss);
+
+if (getsockname(fd, (struct sockaddr *) &ss, &sslen) < 0)
+  return -1;
+
+return (int) ss.ss_family;
+}
+
+
+
+
+/*************************************************
 *       Lookup DSCP settings for a socket        *
 *************************************************/