summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/doc-docbook/spec.xfpt24
-rw-r--r--doc/doc-txt/ChangeLog2
-rw-r--r--doc/doc-txt/NewStuff10
-rw-r--r--src/src/acl.c47
-rw-r--r--src/src/functions.h1
-rw-r--r--src/src/ip.c31
6 files changed, 108 insertions, 7 deletions
diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt
index 3c5f5bd11..b8507f965 100644
--- a/doc/doc-docbook/spec.xfpt
+++ b/doc/doc-docbook/spec.xfpt
@@ -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"
diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog
index 1e8063bf3..3739345af 100644
--- a/doc/doc-txt/ChangeLog
+++ b/doc/doc-txt/ChangeLog
@@ -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
diff --git a/doc/doc-txt/NewStuff b/doc/doc-txt/NewStuff
index e33d2858c..7b0da6854 100644
--- a/doc/doc-txt/NewStuff
+++ b/doc/doc-txt/NewStuff
@@ -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
diff --git a/src/src/acl.c b/src/src/acl.c
index 5b5390d8d..505ccf949 100644
--- a/src/src/acl.c
+++ b/src/src/acl.c
@@ -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;
diff --git a/src/src/functions.h b/src/src/functions.h
index 7fea6ff5c..3e78aa639 100644
--- a/src/src/functions.h
+++ b/src/src/functions.h
@@ -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);
diff --git a/src/src/ip.c b/src/src/ip.c
index 2be68240c..11f0fd88b 100644
--- a/src/src/ip.c
+++ b/src/src/ip.c
@@ -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 *
*************************************************/