diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/src/acl.c | 47 | ||||
-rw-r--r-- | src/src/functions.h | 1 | ||||
-rw-r--r-- | src/src/ip.c | 31 |
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 * *************************************************/ |