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 3c5f5bd113622694c0227cfb0f829bc6d4177351..b8507f9655808a388ddab4e2799704f3f3d6ecb8 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 1e8063bf3d7556ac4ee41015044c0fca656cd705..3739345af45b888b0c664f0b1d2d97f037bdbbcc 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 e33d2858c3491d4726cdea5cf07aafb2424a373c..7b0da68548e9d0541f2c29c216b743b826c3d1cb 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 5b5390d8d3d753a9544483b247b76233196fe4ff..505ccf9491a7fcbcf9123834826605e8a71003a7 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 7fea6ff5ccf6eae65b2e62223a9872d0a75780dc..3e78aa639d62d7273d0e086cc300bbcbf3f11bcc 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 2be68240c4975efe75bb345879f615e972ed7162..11f0fd88b17240881eeae0eaee36dd1f8e8ac9bb 100644 (file)
@@ -361,6 +361,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        *
 *************************************************/