static void dump_log_data( int fd, struct service_config *scp, int tab_level ) { struct log *lp = SC_LOG( scp ) ; struct filelog *flp ; int i ; switch ( LOG_GET_TYPE( lp ) ) { case L_NONE: tabprint( fd, tab_level, "No logging\n" ) ; return ; case L_COMMON_FILE: tabprint( fd, tab_level, "Logging to common log file\n" ) ; break ; case L_FILE: flp = LOG_GET_FILELOG( lp ) ; tabprint( fd, tab_level, "Logging to file: %s", flp->fl_filename ) ; if ( FILELOG_SIZE_CONTROL( flp ) ) Sprint( fd, " (soft=%d hard=%d)\n", flp->fl_soft_limit, flp->fl_hard_limit ) ; else Sprint( fd, " (no limits)\n" ) ; break ; case L_SYSLOG: tabprint( fd, tab_level, "Logging to syslog. Facility = %s, level = %s\n", nv_get_name( syslog_facilities, lp->l_sl.sl_facility ), nv_get_name( syslog_levels, lp->l_sl.sl_level ) ) ; break ; } tabprint( fd, tab_level, "Log_on_success flags =" ) ; for ( i = 0 ; success_log_options[ i ].name != NULL ; i++ ) if ( M_IS_SET( SC_LOG_ON_SUCCESS(scp), success_log_options[ i ].value ) ) Sprint( fd, " %s", success_log_options[ i ].name ) ; Sputchar( fd, '\n' ) ; tabprint( fd, tab_level, "Log_on_failure flags =" ) ; for ( i = 0 ; failure_log_options[ i ].name != NULL ; i++ ) if ( M_IS_SET( SC_LOG_ON_FAILURE(scp), failure_log_options[ i ].value ) ) Sprint( fd, " %s", failure_log_options[ i ].name ) ; Sputchar( fd, '\n' ) ; }
/* This returns a pointer to a local static stack variable. * The behavior is a remnant of inet_ntoa() behavior. */ const char *conn_addrstr( const connection_s *cp ) { static char name[NI_MAXHOST]; unsigned int len = 0; if( !M_IS_SET( (cp)->co_flags, COF_HAVE_ADDRESS ) ) return "<no address>"; if( cp->co_remote_address.sa.sa_family == AF_INET ) len = sizeof(struct sockaddr_in); else if( cp->co_remote_address.sa.sa_family == AF_INET6 ) len = sizeof(struct sockaddr_in6); if( getnameinfo( &cp->co_remote_address.sa, len, name, NI_MAXHOST, NULL, 0, NI_NUMERICHOST ) ) { return "<no address>"; } return name; }
/* This function gets called from child.c after we have been forked */ void redir_handler( struct server *serp ) { struct service *sp = SERVER_SERVICE( serp ); struct service_config *scp = SVC_CONF( sp ); int RedirDescrip = SERVER_FD( serp ); int maxfd, num_read, num_wrote=0, ret=0; unsigned int sin_len = 0; unsigned long bytes_in = 0, bytes_out = 0; int no_to_nagle = 1; int on = 1, v6on; char buff[NET_BUFFER]; fd_set rdfd, msfd; struct timeval *timep = NULL; const char *func = "redir_handler"; union xsockaddr serveraddr ; if( signal(SIGPIPE, redir_sigpipe) == SIG_ERR ) msg(LOG_ERR, func, "unable to setup signal handler"); close_all_svc_descriptors(); /* If it's a tcp service we are redirecting */ if( scp->sc_protocol.value == IPPROTO_TCP ) { memcpy(&serveraddr, scp->sc_redir_addr, sizeof(serveraddr)); if( serveraddr.sa_in.sin_family == AF_INET ) { sin_len = sizeof( struct sockaddr_in ); RedirServerFd = socket(AF_INET, SOCK_STREAM, 0); } else if( serveraddr.sa_in.sin_family == AF_INET6 ) { sin_len = sizeof( struct sockaddr_in6 ); RedirServerFd = socket(AF_INET6, SOCK_STREAM, 0); } else { msg(LOG_ERR, func, "not a valid protocol. Use IPv4 or IPv6."); exit(0); } if( RedirServerFd < 0 ) { msg(LOG_ERR, func, "cannot create socket: %m"); exit(0); } if( SC_IPV6( scp ) ) { if( SC_V6ONLY( scp ) ) { v6on = 1; } else { v6on = 0; } #ifdef IPV6_V6ONLY if( setsockopt(RedirServerFd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&v6on, sizeof(v6on)) < 0 ) { msg( LOG_ERR, func, "Setting IPV6_V6ONLY option failed (%m)" ); } #endif } if( SC_KEEPALIVE( scp ) ) if (setsockopt(RedirServerFd, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, sizeof( on ) ) < 0 ) msg(LOG_ERR, func, "setsockopt SO_KEEPALIVE RedirServerFd failed: %m"); if( serveraddr.sa_in.sin_family == AF_INET ) serveraddr.sa_in.sin_port = htons(serveraddr.sa_in.sin_port); if( serveraddr.sa_in.sin_family == AF_INET6 ) serveraddr.sa_in6.sin6_port = htons(serveraddr.sa_in6.sin6_port); if( connect(RedirServerFd, &serveraddr.sa, sin_len) < 0 ) { msg(LOG_ERR, func, "can't connect to remote host %s: %m", xaddrname( &serveraddr ) ); exit(0); } /* connection now established */ if (setsockopt(RedirServerFd, IPPROTO_TCP, TCP_NODELAY, (char *) &no_to_nagle, sizeof( on ) ) < 0) { msg(LOG_ERR, func, "setsockopt RedirServerFd failed: %m"); } if (setsockopt(RedirDescrip, IPPROTO_TCP, TCP_NODELAY, (char *) &no_to_nagle, sizeof( on ) ) < 0) { msg(LOG_ERR, func, "setsockopt RedirDescrip failed: %m"); } maxfd = (RedirServerFd > RedirDescrip)?RedirServerFd:RedirDescrip; FD_ZERO(&msfd); FD_SET(RedirDescrip, &msfd); FD_SET(RedirServerFd, &msfd); while(1) { memcpy(&rdfd, &msfd, sizeof(rdfd)); if (select(maxfd + 1, &rdfd, (fd_set *)0, (fd_set *)0, timep) <= 0) { /* place for timeout code, currently does not time out */ break; } if (FD_ISSET(RedirDescrip, &rdfd)) { do { num_read = read(RedirDescrip, buff, sizeof(buff)); if (num_read == -1 && errno == EINTR) continue; if (num_read <= 0) goto REDIROUT; bytes_in += num_read; } while (num_read < 0); /* Loop until we have written everything * that was read */ num_wrote = 0; while( num_wrote < num_read ) { ret = write(RedirServerFd, buff + num_wrote, num_read - num_wrote); if (ret == -1 && errno == EINTR) continue; if (ret <= 0) goto REDIROUT; num_wrote += ret; } } if (FD_ISSET(RedirServerFd, &rdfd)) { do { num_read = read(RedirServerFd, buff, sizeof(buff)); if (num_read == -1 && errno == EINTR) continue; if (num_read <= 0) goto REDIROUT; bytes_out += num_read; } while (num_read < 0); /* Loop until we have written everything * that was read */ num_wrote = 0; while( num_wrote < num_read ) { ret = write(RedirDescrip, buff + num_wrote, num_read - num_wrote); if (ret == -1 && errno == EINTR) continue; if (ret <= 0) goto REDIROUT; num_wrote += ret; } } } REDIROUT: if( M_IS_SET( (scp)->sc_log_on_success, LO_TRAFFIC ) ) { svc_logprint( SERVER_CONNSERVICE( serp ), "TRAFFIC", "in=%lu(bytes) out=%lu(bytes)", bytes_in, bytes_out ); } exit(0); } msg(LOG_ERR, func, "redirect with any protocol other than tcp is not supported at this time."); exit(0); }
/* * Print info about service scp to file descriptor fd */ void sc_dump( struct service_config *scp, int fd, int tab_level, bool_int is_defaults ) { const struct name_value *nvp ; unsigned u ; char **pp ; if ( is_defaults ) tabprint( fd, tab_level, "Service defaults\n" ) ; else tabprint( fd, tab_level, "Service configuration: %s\n", SC_NAME(scp) ) ; if ( ! is_defaults ) { tabprint( fd, tab_level+1, "id = %s\n", SC_ID(scp) ) ; if ( ! M_ARE_ALL_CLEAR( SC_XFLAGS(scp) ) ) { tabprint( fd, tab_level+1, "flags =" ) ; for ( nvp = &service_flags[ 0 ] ; nvp->name != NULL ; nvp++ ) if ( M_IS_SET( SC_XFLAGS(scp), nvp->value ) ) Sprint( fd, " %s", nvp->name ) ; Sputchar( fd, '\n' ) ; } if ( ! M_ARE_ALL_CLEAR( SC_TYPE(scp) ) ) { tabprint( fd, tab_level+1, "type =" ) ; for ( nvp = &service_types[ 0 ] ; nvp->name != NULL ; nvp++ ) if ( M_IS_SET( SC_TYPE(scp), nvp->value ) ) Sprint( fd, " %s", nvp->name ) ; Sputchar( fd, '\n' ) ; } tabprint( fd, tab_level+1, "socket_type = %s\n", nv_get_name( socket_types, SC_SOCKET_TYPE(scp) ) ) ; tabprint( fd, tab_level+1, "Protocol (name,number) = (%s,%d)\n", SC_PROTONAME(scp), SC_PROTOVAL(scp) ) ; if ( SC_SPECIFIED( scp, A_PORT ) ) tabprint( fd, tab_level+1, "port = %d\n", SC_PORT(scp) ) ; } if ( SC_SPECIFIED( scp, A_INSTANCES ) ) { if ( SC_INSTANCES(scp) == UNLIMITED ) tabprint( fd, tab_level+1, "Instances = UNLIMITED\n" ) ; else tabprint( fd, tab_level+1, "Instances = %d\n", SC_INSTANCES(scp) ) ; } if ( SC_SPECIFIED( scp, A_WAIT ) ) { if ( SC_WAIT(scp) ) tabprint( fd, tab_level+1, "wait = yes\n" ) ; else tabprint( fd, tab_level+1, "wait = no\n" ) ; } if ( SC_SPECIFIED( scp, A_USER ) ) tabprint( fd, tab_level+1, "user = %d\n", SC_UID(scp) ) ; if ( SC_SPECIFIED( scp, A_GROUP ) ) tabprint( fd, tab_level+1, "group = %d\n", SC_GID(scp) ) ; if ( SC_SPECIFIED( scp, A_GROUPS ) ) { if (SC_GROUPS(scp) == 1) tabprint( fd, tab_level+1, "Groups = yes\n" ); else tabprint( fd, tab_level+1, "Groups = no\n" ); } if ( SC_SPECIFIED( scp, A_UMASK ) ) tabprint( fd, tab_level+1, "umask = %o\n", SC_UMASK(scp) ) ; if ( SC_SPECIFIED( scp, A_NICE ) ) tabprint( fd, tab_level+1, "Nice = %d\n", SC_NICE(scp) ) ; if ( SC_SPECIFIED( scp, A_CPS ) ) tabprint( fd, tab_level+1, "CPS = max conn:%lu wait:%lu\n", SC_TIME_CONN_MAX(scp), SC_TIME_WAIT(scp) ); if ( SC_SPECIFIED( scp, A_PER_SOURCE ) ) tabprint( fd, tab_level+1, "PER_SOURCE = %d\n", SC_PER_SOURCE(scp) ); if ( SC_SPECIFIED( scp, A_BIND ) ) { if ( SC_BIND_ADDR(scp) ) { char bindname[NI_MAXHOST]; unsigned int len = 0; if( SC_BIND_ADDR(scp)->sa.sa_family == AF_INET ) len = sizeof(struct sockaddr_in); else len = sizeof(struct sockaddr_in6); memset(bindname, 0, sizeof(bindname)); if( getnameinfo(&SC_BIND_ADDR(scp)->sa, len, bindname, NI_MAXHOST, NULL, 0, 0) != 0 ) strcpy(bindname, "unknown"); tabprint( fd, tab_level+1, "Bind = %s\n", bindname ); } else if ( SC_ORIG_BIND_ADDR(scp) ) { tabprint( fd, tab_level+1, "Bind = %s\n", SC_ORIG_BIND_ADDR(scp) ); } else { /* This should NEVER happen */ msg(LOG_ERR, "sc_dump", "bad configuration for %s:", SC_NAME(scp)); } } else tabprint( fd, tab_level+1, "Bind = All addresses.\n" ); if ( ! is_defaults ) { if ( (! SC_IS_INTERNAL( scp )) && (SC_REDIR_ADDR(scp) == NULL) ) { tabprint( fd, tab_level+1, "Server = %s\n", SC_SERVER(scp) ) ; tabprint( fd, tab_level+1, "Server argv =" ) ; if ( SC_SERVER_ARGV(scp) ) { for ( pp = SC_SERVER_ARGV(scp) ; *pp ; pp++ ) Sprint( fd, " %s", *pp ) ; } else Sprint( fd, " (NULL)"); Sputchar( fd, '\n' ) ; } #ifdef LIBWRAP if ( SC_LIBWRAP(scp) != NULL ) { tabprint( fd, tab_level + 1, "Libwrap = %s\n", SC_LIBWRAP(scp) ); } #endif if ( SC_REDIR_ADDR(scp) != NULL ) { char redirname[NI_MAXHOST]; unsigned int len = 0; if( SC_REDIR_ADDR(scp)->sa.sa_family == AF_INET ) len = sizeof(struct sockaddr_in); if( SC_REDIR_ADDR(scp)->sa.sa_family == AF_INET6 ) len = sizeof(struct sockaddr_in6); memset(redirname, 0, sizeof(redirname)); if( getnameinfo(&SC_REDIR_ADDR(scp)->sa, len, redirname, NI_MAXHOST, NULL, 0, 0) != 0 ) strcpy(redirname, "unknown"); tabprint( fd, tab_level+1, "Redirect = %s:%d\n", redirname, SC_REDIR_ADDR(scp)->sa_in.sin_port ); } if ( SC_IS_RPC( scp ) ) { struct rpc_data *rdp = SC_RPCDATA( scp ) ; tabprint( fd, tab_level+1, "RPC data\n" ) ; tabprint( fd, tab_level+2, "program number = %ld\n", rdp->rd_program_number ) ; tabprint( fd, tab_level+2, "rpc_version = " ) ; if ( rdp->rd_min_version == rdp->rd_max_version ) Sprint( fd, "%ld\n", rdp->rd_min_version ) ; else Sprint( fd, "%ld-%ld\n", rdp->rd_min_version, rdp->rd_max_version ) ; } if ( SC_SPECIFIED( scp, A_ACCESS_TIMES ) ) { tabprint( fd, tab_level+1, "Access times =" ) ; ti_dump( SC_ACCESS_TIMES(scp), fd ) ; Sputchar ( fd, '\n' ) ; } } /* This is important enough that each service should list it. */ tabprint( fd, tab_level+1, "Only from: " ) ; if ( SC_ONLY_FROM(scp) ) { /* Next check is done since -= doesn't zero out lists. */ if ( pset_count(SC_ONLY_FROM(scp)) == 0) Sprint( fd, "All sites" ); else addrlist_dump( SC_ONLY_FROM(scp), fd ) ; } else Sprint( fd, "All sites" ); Sputchar( fd, '\n' ) ; /* This is important enough that each service should list it. */ tabprint( fd, tab_level+1, "No access: " ) ; if ( SC_NO_ACCESS(scp) ) { /* Next check is done since -= doesn't zero out lists. */ if ( pset_count(SC_NO_ACCESS(scp)) == 0) Sprint( fd, "No blocked sites" ); else addrlist_dump( SC_NO_ACCESS(scp), fd ) ; } else Sprint( fd, "No blocked sites" ); Sputchar( fd, '\n' ) ; if ( SC_SENSOR(scp) ) { tabprint( fd, tab_level+1, "Deny Time: " ) ; Sprint( fd, "%d\n", SC_DENY_TIME(scp)); } dump_log_data( fd, scp, tab_level+1 ) ; if ( SC_IS_PRESENT( scp, A_PASSENV ) ) { tabprint( fd, tab_level+1, "Passenv =" ) ; for ( u = 0 ; u < pset_count( SC_PASS_ENV_VARS(scp) ) ; u++ ) Sprint( fd, " %s", (char *) pset_pointer( SC_PASS_ENV_VARS(scp), u ) ) ; Sputchar ( fd, '\n' ) ; } if ( ! is_defaults ) if ( SC_SPECIFIED( scp, A_ENV ) ) { tabprint( fd, tab_level+1, "Environment additions:\n" ) ; for ( u = 0 ; u < pset_count( SC_ENV_VAR_DEFS(scp) ) ; u++ ) tabprint( fd, tab_level+2, "%s\n", (char *) pset_pointer( SC_ENV_VAR_DEFS(scp), u ) ) ; } if ( SC_ENV( scp )->env_type == CUSTOM_ENV ) { tabprint( fd, tab_level+1, "Environment strings:\n" ) ; for ( pp = env_getvars( SC_ENV( scp )->env_handle ) ; *pp ; pp++ ) tabprint( fd, tab_level+2, "%s\n", *pp ) ; } Sflush( fd ) ; }