static void anvil_service_done(VSTREAM *client_stream, char *unused_service, char **unused_argv) { ANVIL_LOCAL *anvil_local; const char *myname = "anvil_service_done"; if (msg_verbose) msg_info("%s fd=%d stream=0x%lx", myname, vstream_fileno(client_stream), (unsigned long) client_stream); /* * Look up the local server, and get rid of any remote connection state * that we still have for this local server. Do not destroy remote client * status information before it expires. */ if ((anvil_local = (ANVIL_LOCAL *) vstream_context(client_stream)) != 0) { if (msg_verbose) msg_info("%s: anvil_local 0x%lx", myname, (unsigned long) anvil_local); ANVIL_LOCAL_DROP_ALL(client_stream, anvil_local); myfree((char *) anvil_local); } else if (msg_verbose) msg_info("client socket not found for fd=%d", vstream_fileno(client_stream)); }
static void multi_server_execute(int unused_event, char *context) { VSTREAM *stream = (VSTREAM *) context; HTABLE *attr = (vstream_flags(stream) == multi_server_saved_flags ? (HTABLE *) vstream_context(stream) : 0); if (multi_server_lock != 0 && myflock(vstream_fileno(multi_server_lock), INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0) msg_fatal("select unlock: %m"); /* * Do not bother the application when the client disconnected. Don't drop * the already accepted client request after "postfix reload"; that would * be rude. */ if (peekfd(vstream_fileno(stream)) > 0) { if (master_notify(var_pid, multi_server_generation, MASTER_STAT_TAKEN) < 0) /* void */ ; multi_server_service(stream, multi_server_name, multi_server_argv); if (master_notify(var_pid, multi_server_generation, MASTER_STAT_AVAIL) < 0) multi_server_abort(EVENT_NULL_TYPE, EVENT_NULL_CONTEXT); } else { multi_server_disconnect(stream); } if (attr) htable_free(attr, myfree); }
static void anvil_remote_disconnect(VSTREAM *client_stream, const char *ident) { ANVIL_REMOTE *anvil_remote; ANVIL_LOCAL *anvil_local; const char *myname = "anvil_remote_disconnect"; if (msg_verbose) msg_info("%s fd=%d stream=0x%lx ident=%s", myname, vstream_fileno(client_stream), (unsigned long) client_stream, ident); /* * Update local and remote info if this remote connection is listed for * this local server. */ if ((anvil_local = (ANVIL_LOCAL *) vstream_context(client_stream)) != 0 && (anvil_remote = (ANVIL_REMOTE *) htable_find(anvil_remote_map, ident)) != 0 && ANVIL_LOCAL_REMOTE_LINKED(anvil_local, anvil_remote)) { ANVIL_REMOTE_DROP_ONE(anvil_remote); ANVIL_LOCAL_DROP_ONE(anvil_local, anvil_remote); } if (msg_verbose) msg_info("%s: anvil_local 0x%lx", myname, (unsigned long) anvil_local); /* * Respond to the local server. */ attr_print_plain(client_stream, ATTR_FLAG_NONE, ATTR_TYPE_INT, ANVIL_ATTR_STATUS, ANVIL_STAT_OK, ATTR_TYPE_END); }
void smtpd_peer_init(SMTPD_STATE *state) { /* * Initialize. */ if (proto_info == 0) proto_info = inet_proto_info(); /* * Prepare for partial initialization after error. */ memset((void *) &(state->sockaddr), 0, sizeof(state->sockaddr)); state->sockaddr_len = 0; state->name = 0; state->reverse_name = 0; state->addr = 0; state->namaddr = 0; state->rfc_addr = 0; state->port = 0; state->dest_addr = 0; state->dest_port = 0; /* * Determine the remote SMTP client address and port. * * XXX In stand-alone mode, don't assume that the peer will be a local * process. That could introduce a gaping hole when the SMTP daemon is * hooked up to the network via inetd or some other super-server. */ if (vstream_context(state->client) != 0) { smtpd_peer_from_pass_attr(state); if (*var_smtpd_uproxy_proto != 0) msg_warn("ignoring non-empty %s setting behind postscreen", VAR_SMTPD_UPROXY_PROTO); } else if (SMTPD_STAND_ALONE(state) || *var_smtpd_uproxy_proto == 0) { smtpd_peer_from_default(state); } else { smtpd_peer_from_proxy(state); } /* * Determine the remote SMTP client hostname. Note: some of the handlers * above provide surrogate endpoint information in case of error. In that * case, leave the surrogate information alone. */ if (state->name == 0) smtpd_peer_sockaddr_to_hostname(state); /* * Do the name[addr]:port formatting for pretty reports. */ state->namaddr = SMTPD_BUILD_NAMADDRPORT(state->name, state->addr, state->port); }
static void smtpd_peer_from_pass_attr(SMTPD_STATE *state) { HTABLE *attr = (HTABLE *) vstream_context(state->client); const char *cp; /* * Extract the client endpoint information from the attribute hash. */ if ((cp = htable_find(attr, MAIL_ATTR_ACT_CLIENT_ADDR)) == 0) msg_fatal("missing client address from proxy"); if (strrchr(cp, ':') != 0) { if (valid_ipv6_hostaddr(cp, DO_GRIPE) == 0) msg_fatal("bad IPv6 client address syntax from proxy: %s", cp); state->addr = mystrdup(cp); state->rfc_addr = concatenate(IPV6_COL, cp, (char *) 0); state->addr_family = AF_INET6; } else { if (valid_ipv4_hostaddr(cp, DO_GRIPE) == 0) msg_fatal("bad IPv4 client address syntax from proxy: %s", cp); state->addr = mystrdup(cp); state->rfc_addr = mystrdup(cp); state->addr_family = AF_INET; } if ((cp = htable_find(attr, MAIL_ATTR_ACT_CLIENT_PORT)) == 0) msg_fatal("missing client port from proxy"); if (valid_hostport(cp, DO_GRIPE) == 0) msg_fatal("bad TCP client port number syntax from proxy: %s", cp); state->port = mystrdup(cp); /* * The Dovecot authentication server needs the server IP address. */ if ((cp = htable_find(attr, MAIL_ATTR_ACT_SERVER_ADDR)) == 0) msg_fatal("missing server address from proxy"); if (valid_hostaddr(cp, DO_GRIPE) == 0) msg_fatal("bad IPv6 server address syntax from proxy: %s", cp); state->dest_addr = mystrdup(cp); if ((cp = htable_find(attr, MAIL_ATTR_ACT_SERVER_PORT)) == 0) msg_fatal("missing server port from proxy"); if (valid_hostport(cp, DO_GRIPE) == 0) msg_fatal("bad TCP server port number syntax from proxy: %s", cp); state->dest_port = mystrdup(cp); /* * Convert the client address from string to binary form. */ smtpd_peer_hostaddr_to_sockaddr(state); }
static ANVIL_REMOTE *anvil_remote_conn_update(VSTREAM *client_stream, const char *ident) { ANVIL_REMOTE *anvil_remote; ANVIL_LOCAL *anvil_local; const char *myname = "anvil_remote_conn_update"; if (msg_verbose) msg_info("%s fd=%d stream=0x%lx ident=%s", myname, vstream_fileno(client_stream), (unsigned long) client_stream, ident); /* * Look up remote connection count information. Update remote connection * rate information. Simply reset the counter every var_anvil_time_unit * seconds. This is easier than maintaining a moving average and it gives * a quicker response to tresspassers. */ if ((anvil_remote = (ANVIL_REMOTE *) htable_find(anvil_remote_map, ident)) == 0) { anvil_remote = (ANVIL_REMOTE *) mymalloc(sizeof(*anvil_remote)); ANVIL_REMOTE_FIRST_CONN(anvil_remote, ident); htable_enter(anvil_remote_map, ident, (char *) anvil_remote); if (max_cache_size < anvil_remote_map->used) { max_cache_size = anvil_remote_map->used; max_cache_time = event_time(); } } else { ANVIL_REMOTE_NEXT_CONN(anvil_remote); } /* * Record this connection under the local server information, so that we * can clean up all its connection state when the local server goes away. */ if ((anvil_local = (ANVIL_LOCAL *) vstream_context(client_stream)) == 0) { anvil_local = (ANVIL_LOCAL *) mymalloc(sizeof(*anvil_local)); ANVIL_LOCAL_INIT(anvil_local); vstream_control(client_stream, VSTREAM_CTL_CONTEXT, (void *) anvil_local, VSTREAM_CTL_END); } ANVIL_LOCAL_ADD_ONE(anvil_local, anvil_remote); if (msg_verbose) msg_info("%s: anvil_local 0x%lx", myname, (unsigned long) anvil_local); return (anvil_remote); }
static void psc_dnsbl_receive(int event, void *context) { const char *myname = "psc_dnsbl_receive"; VSTREAM *stream = (VSTREAM *) context; PSC_DNSBL_SCORE *score; PSC_DNSBL_HEAD *head; PSC_DNSBL_SITE *site; ARGV *reply_argv; int request_id; int dnsbl_ttl; PSC_CLEAR_EVENT_REQUEST(vstream_fileno(stream), psc_dnsbl_receive, context); /* * Receive the DNSBL lookup result. * * This is preliminary code to explore the field. Later, DNSBL lookup will * be handled by an UDP-based DNS client that is built directly into some * Postfix daemon. * * Don't bother looking up the blocklist score when the client IP address is * not listed at the DNSBL. * * Don't panic when the blocklist score no longer exists. It may be deleted * when the client triggers a "drop" action after pregreet, when the * client does not pregreet and the DNSBL reply arrives late, or when the * client triggers a "drop" action after hanging up. */ if (event == EVENT_READ && attr_scan(stream, ATTR_FLAG_STRICT, RECV_ATTR_STR(MAIL_ATTR_RBL_DOMAIN, reply_dnsbl), RECV_ATTR_STR(MAIL_ATTR_ACT_CLIENT_ADDR, reply_client), RECV_ATTR_INT(MAIL_ATTR_LABEL, &request_id), RECV_ATTR_STR(MAIL_ATTR_RBL_ADDR, reply_addr), RECV_ATTR_INT(MAIL_ATTR_TTL, &dnsbl_ttl), ATTR_TYPE_END) == 5 && (score = (PSC_DNSBL_SCORE *) htable_find(dnsbl_score_cache, STR(reply_client))) != 0 && score->request_id == request_id) { /* * Run this response past all applicable DNSBL filters and update the * blocklist score for this client IP address. * * Don't panic when the DNSBL domain name is not found. The DNSBLOG * server may be messed up. */ if (msg_verbose > 1) msg_info("%s: client=\"%s\" score=%d domain=\"%s\" reply=\"%d %s\"", myname, STR(reply_client), score->total, STR(reply_dnsbl), dnsbl_ttl, STR(reply_addr)); head = (PSC_DNSBL_HEAD *) htable_find(dnsbl_site_cache, STR(reply_dnsbl)); if (head == 0) { /* Bogus domain. Do nothing. */ } else if (*STR(reply_addr) != 0) { /* DNS reputation record(s) found. */ reply_argv = 0; for (site = head->first; site != 0; site = site->next) { if (site->byte_codes == 0 || psc_dnsbl_match(site->byte_codes, reply_argv ? reply_argv : (reply_argv = argv_split(STR(reply_addr), " ")))) { if (score->dnsbl_name == 0 || score->dnsbl_weight < site->weight) { score->dnsbl_name = head->safe_dnsbl; score->dnsbl_weight = site->weight; } score->total += site->weight; if (msg_verbose > 1) msg_info("%s: filter=\"%s\" weight=%d score=%d", myname, site->filter ? site->filter : "null", site->weight, score->total); } /* As with dnsblog(8), a value < 0 means no reply TTL. */ if (site->weight > 0) { if (score->fail_ttl < 0 || score->fail_ttl > dnsbl_ttl) score->fail_ttl = dnsbl_ttl; } else { if (score->pass_ttl < 0 || score->pass_ttl > dnsbl_ttl) score->pass_ttl = dnsbl_ttl; } } if (reply_argv != 0) argv_free(reply_argv); } else { /* No DNS reputation record found. */ for (site = head->first; site != 0; site = site->next) { /* As with dnsblog(8), a value < 0 means no reply TTL. */ if (site->weight > 0) { if (score->pass_ttl < 0 || score->pass_ttl > dnsbl_ttl) score->pass_ttl = dnsbl_ttl; } else { if (score->fail_ttl < 0 || score->fail_ttl > dnsbl_ttl) score->fail_ttl = dnsbl_ttl; } } } /* * Notify the requestor(s) that the result is ready to be picked up. * If this call isn't made, clients have to sit out the entire * pre-handshake delay. */ score->pending_lookups -= 1; if (score->pending_lookups == 0) PSC_CALL_BACK_NOTIFY(score, PSC_NULL_EVENT); } else if (event == EVENT_TIME) { msg_warn("dnsblog reply timeout %ds for %s", var_psc_dnsbl_tmout, (char *) vstream_context(stream)); } /* Here, score may be a null pointer. */ vstream_fclose(stream); }