void ConvertDefaultIPToSocketIP(char const *attr_name,char const *old_expr_string,char **new_expr_string,Stream& s) { *new_expr_string = NULL; if( !enable_convert_default_IP_to_socket_IP ) { return; } if(!is_sender_ip_attr(attr_name)) { return; } char const *my_default_ip = my_ip_string(); char const *my_sock_ip = s.my_ip_str(); if(!my_default_ip || !my_sock_ip) { return; } if(strcmp(my_default_ip,my_sock_ip) == 0) { return; } condor_sockaddr sock_addr; //if(is_loopback_net_str(my_sock_ip)) { if (sock_addr.from_ip_string(my_sock_ip) && sock_addr.is_loopback()) { // We must be talking to another daemon on the same // machine as us. We don't want to replace the default IP // with this one, since nobody outside of this machine // will be able to contact us on that IP. return; } if( !IPMatchesNetworkInterfaceSetting(my_sock_ip) ) { return; } char const *ref = strstr(old_expr_string,my_default_ip); if(ref) { // the match must not be followed by any trailing digits // GOOD: <MMM.MMM.M.M:port?p> (where M is a matching digit) // BAD: <MMM.MMM.M.MN:port?p> (where N is a non-matching digit) if( isdigit(ref[strlen(my_default_ip)]) ) { ref = NULL; } } if(ref) { // Replace the default IP address with the one I am actually using. int pos = ref-old_expr_string; // position of the reference int my_default_ip_len = strlen(my_default_ip); int my_sock_ip_len = strlen(my_sock_ip); *new_expr_string = (char *)malloc(strlen(old_expr_string) + my_sock_ip_len - my_default_ip_len + 1); ASSERT(*new_expr_string); strncpy(*new_expr_string, old_expr_string,pos); strcpy(*new_expr_string+pos, my_sock_ip); strcpy(*new_expr_string+pos+my_sock_ip_len, old_expr_string+pos+my_default_ip_len); dprintf(D_NETWORK,"Replaced default IP %s with connection IP %s " "in outgoing ClassAd attribute %s.\n", my_default_ip,my_sock_ip,attr_name); } }
void ConvertDefaultIPToSocketIP(char const * attr_name, std::string & expr_string, Stream & s ) { static bool loggedNullDCMessage = false; static bool loggedConfigMessage = false; // We can't practically do a conversion if daemonCore isn't present; this // happens in standard universe. We can't move this test into // ConfigConvertDefaultIPToSocketIP because it gets called before // daemonCore is created. if( daemonCore == NULL ) { if( ! loggedNullDCMessage ) { dprintf( D_NETWORK | D_VERBOSE, "Address rewriting: disabled: no daemon core.\n" ); loggedNullDCMessage = true; } return; } if( ! enable_convert_default_IP_to_socket_IP ) { if( ! loggedConfigMessage ) { dprintf( D_NETWORK | D_VERBOSE, "Address rewriting: disabled: by configuration.\n" ); loggedConfigMessage = true; } return; } if( ! is_sender_ip_attr( attr_name ) ) { // Reduce log spam. Since all of our subsequent messages include the // attribute name, we don't have to print a message noting that we // tried to rewrite it. // dprintf( D_NETWORK | D_VERBOSE, "Address rewriting: '%s' is not an attribute which might contain the sender's IP address.\n", attr_name ); return; } // Skip if Stream doesn't have address associated with it condor_sockaddr connectionSA; if( ! connectionSA.from_ip_string( s.my_ip_str() ) ) { dprintf( D_NETWORK | D_VERBOSE, "Address rewriting: failed for attribute '%s' (%s): failed to generate socket address from stream's IP string (%s).\n", attr_name, expr_string.c_str(), s.my_ip_str() ); return; } // Skip if it's not a string literal. if( * ( expr_string.rbegin() ) != '"' ) { dprintf( D_NETWORK | D_VERBOSE, "Address rewriting: failed for attribute '%s' (%s): failed to parse. Missing closing double quotation mark.\n", attr_name, expr_string.c_str() ); return; } const char * delimiter = " = \""; size_t delimpos = expr_string.find( delimiter ); // Skip if doesn't look like a string if( delimpos == std::string::npos ) { dprintf( D_NETWORK | D_VERBOSE, "Address rewriting: failed for attribute '%s' (%s): failed to parse. Missing assignment.\n", attr_name, expr_string.c_str() ); return; } size_t string_start_pos = delimpos + strlen( delimiter ); // string_end_pos is one beyond last character of String literal. size_t string_end_pos = expr_string.length() - 1; size_t string_len = string_end_pos - string_start_pos; // Skip if it doesn't look like a Sinful if( expr_string[string_start_pos] != '<' ) { dprintf( D_NETWORK | D_VERBOSE, "Address rewriting: failed for attribute '%s' (%s): failed to parse. Missing opening <.\n", attr_name, expr_string.c_str() ); return; } if( expr_string[string_end_pos - 1] != '>' ) { dprintf( D_NETWORK | D_VERBOSE, "Address rewriting: failed for attribute '%s' (%s): failed to parse. Missing closing >.\n", attr_name, expr_string.c_str() ); return; } std::string adSinfulString = expr_string.substr( string_start_pos, string_len); std::string commandPortSinfulString = daemonCore->InfoCommandSinfulString(); Sinful adSinful( adSinfulString.c_str() ); condor_sockaddr adSA; adSA.from_sinful( adSinful.getSinful() ); bool rewrite_port = true; if (commandPortSinfulString == adSinfulString) { dprintf( D_NETWORK | D_VERBOSE, "Address rewriting: refused for attribute %s (%s): clients now choose addresses.\n", attr_name, expr_string.c_str() ); return; } else if (param_boolean("SHARED_PORT_ADDRESS_REWRITING", false)) { // // Wait a minute -- isn't this only supposed to happen in the collector? // const std::vector<Sinful> &commandSinfuls = daemonCore->InfoCommandSinfulStringsMyself(); dprintf(D_NETWORK|D_VERBOSE, "Address rewriting: considering %ld command socket sinfuls.\n", commandSinfuls.size()); bool acceptableMatch = false; std::vector<Sinful>::const_iterator it; for (it = commandSinfuls.begin(); it!=commandSinfuls.end(); it++) { commandPortSinfulString = it->getSinful(); const Sinful &commandPortSinful = *it; // We assume that any sinful on the same shared port server // can also be rewritten. if ((adSinful.getSharedPortID() != NULL) && (strcmp(commandPortSinful.getHost(), adSinful.getHost()) == 0) && (commandPortSinful.getPortNum() == adSinful.getPortNum())) { acceptableMatch = true; break; } dprintf( D_NETWORK | D_VERBOSE, "Address rewriting: refused for attribute %s (%s): the address isn't my default address. (Command socket considered: %s, found in ad: %s)\n", attr_name, expr_string.c_str(), commandPortSinfulString.c_str(), adSinfulString.c_str()); } if (!acceptableMatch) { return; } } else { dprintf( D_NETWORK | D_VERBOSE, "Address rewriting: refused for attribute %s (%s): the address isn't my default address. (Default: %s, found in ad: %s)\n", attr_name, expr_string.c_str(), commandPortSinfulString.c_str(), adSinfulString.c_str()); return; } // // Although it's never useful to rewrite from a non-loopback to a loop- // back address, if there's more than one loopback address on a machine, // (generally but not always because the machine supports more than one // protocol), it's OK to rewrite from one to the other. // // Doing this is any other situation breaks, among other things, // ssh-to-job. (In a design hack, the starter sends its external // address to the startd over the job-update socket, as part of every // job update ClassAd. This causes rewriting to happen, but as the // the startd explicity binds the job-update socket to the loopback // address -- presumambly to ensure that it always works -- we need // to make sure we don't rewrite ATTR_STARTER_IP_ADDR when sending // job updates. *sigh*) // if( (! adSA.is_loopback()) && connectionSA.is_loopback() ) { dprintf( D_NETWORK | D_VERBOSE, "Address rewriting: refused for attribute '%s' (%s): outbound interface is loopback but default interface is not.\n", attr_name, expr_string.c_str() ); return; } if( adSinful.getSharedPortID() != NULL ) { // We're using shared port, so "our" port is actually the // shared port daemon's. We shouldn't be messing with that. // We'll rewrite the host on the bold assumption that shared // port daemon and I both use the same IP addresses. rewrite_port = false; } MyString my_sock_ip = connectionSA.to_ip_string( true ); adSinful.setHost( my_sock_ip.Value() ); if( rewrite_port ) { // connectionSA's port is whatever we happen to be using at the moment; // that will be meaningless if we established the connection. What we // want is the port someone could contact us on. Go rummage for one. int port = daemonCore->find_interface_command_port_do_not_use( connectionSA ); // If port is 0, there is no matching listen socket. There is nothing // useful we can rewrite it do, so just give up and hope the default // is useful to someone. if( port == 0 ) { dprintf( D_NETWORK | D_VERBOSE, "Address rewriting: failed for attribute '%s' (%s): unable to find command port for outbound interface '%s'.\n", attr_name, expr_string.c_str(), s.my_ip_str() ); return; } adSinful.setPort( port ); } if( adSinful.getSinful() == adSinfulString ) { dprintf( D_NETWORK | D_VERBOSE, "Address rewriting: refused for attribute '%s' (%s): socket is using same address as the default one; rewrite would do nothing.\n", attr_name, expr_string.c_str() ); return; } std::string new_expr = expr_string.substr( 0, string_start_pos ); new_expr.append( adSinful.getSinful() ); new_expr.append( expr_string.substr( string_end_pos ) ); expr_string = new_expr; dprintf( D_NETWORK, "Address rewriting: Replaced default IP %s with " "connection IP %s in outgoing ClassAd attribute %s.\n", adSinfulString.c_str(), adSinful.getSinful(), attr_name ); }