summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/src/acl.c47
-rw-r--r--src/src/functions.h1
-rw-r--r--src/src/ip.c31
3 files changed, 79 insertions, 0 deletions
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 *
*************************************************/