/** * Test the connection and protocol */ static void check_connection(Service_T s, Port_T p) { Socket_T socket; volatile int rv = TRUE; char buf[STRLEN]; char report[STRLEN] = {0}; struct timeval t1; struct timeval t2; ASSERT(s && p); /* Get time of connection attempt beginning */ gettimeofday(&t1, NULL); /* Open a socket to the destination INET[hostname:port] or UNIX[pathname] */ socket = socket_create(p); if (!socket) { snprintf(report, STRLEN, "failed, cannot open a connection to %s", Util_portDescription(p, buf, sizeof(buf))); rv = FALSE; goto error; } else DEBUG("'%s' succeeded connecting to %s\n", s->name, Util_portDescription(p, buf, sizeof(buf))); /* Verify that the socket is ready for i|o. TCP sockets are checked anytime, UDP * sockets just when there is no specific protocol test used since the socket_is_ready() * adds 2s delay when used with UDP socket. When there is specific protocol used, we * don't need it for UDP, since the protocol test is sufficient */ if ((socket_get_type(socket) != SOCK_DGRAM || p->protocol->check == check_default) && !socket_is_ready(socket)) { snprintf(report, STRLEN, "connection failed, %s is not ready for i|o -- %s", Util_portDescription(p, buf, sizeof(buf)), STRERROR); rv = FALSE; goto error; } /* Run the protocol verification routine through the socket */ if (! p->protocol->check(socket)) { snprintf(report, STRLEN, "failed protocol test [%s] at %s", p->protocol->name, Util_portDescription(p, buf, sizeof(buf))); rv = FALSE; goto error; } else DEBUG("'%s' succeeded testing protocol [%s] at %s\n", s->name, p->protocol->name, Util_portDescription(p, buf, sizeof(buf))); /* Get time of connection attempt finish */ gettimeofday(&t2, NULL); /* Get the response time */ p->response = (double)(t2.tv_sec - t1.tv_sec) + (double)(t2.tv_usec - t1.tv_usec)/1000000; error: if (socket) socket_free(&socket); if (!rv) { p->response = -1; p->is_available = FALSE; Event_post(s, Event_Connection, STATE_FAILED, p->action, report); } else { p->is_available = TRUE; Event_post(s, Event_Connection, STATE_SUCCEEDED, p->action, "connection succeeded to %s", Util_portDescription(p, buf, sizeof(buf))); } }
/** * Simple DNS test. * * The nameserver is queried for NS record of DNS root. * * @file */ int check_dns(Socket_T socket) { int offset_request = 0; int offset_response = 0; int rc; unsigned char buf[STRLEN]; unsigned char *response = NULL; unsigned char request[19] = { 0x00, /** Request Length field for DNS via TCP */ 0x11, 0x00, /** Transaction ID */ 0x01, 0x01, /** Flags */ 0x00, 0x00, /** Queries count */ 0x01, 0x00, /** Answer resource records count */ 0x00, 0x00, /** Authority resource records count */ 0x00, 0x00, /** Additional resource records count */ 0x00, /** Query: */ 0x00, /** Name: DNS root (empty string) */ 0x00, /** Type: NS */ 0x02, 0x00, /** Class: IN */ 0x01 }; ASSERT(socket); switch (socket_get_type(socket)) { case SOCK_DGRAM: offset_request = 2; /* Skip Length field in request */ offset_response = 0; break; case SOCK_STREAM: offset_request = 0; offset_response = 2; /* Skip Length field in response */ break; default: socket_setError(socket, "DNS: unsupported socket type -- protocol test skipped"); return TRUE; } if (socket_write(socket, (unsigned char *)request + offset_request, sizeof(request) - offset_request) < 0) { socket_setError(socket, "DNS: error sending query -- %s", STRERROR); return FALSE; } /* Response should have at least 14 bytes */ if (socket_read(socket, (unsigned char *)buf, 15) <= 14) { socket_setError(socket, "DNS: error receiving response -- %s", STRERROR); return FALSE; } response = buf + offset_response; /* Compare transaction ID (it should be the same as in our request): */ if (response[0] != 0x00 && response[1] != 0x01) { socket_setError(socket, "DNS: response transaction ID mismatch -- received 0x%x%x, expected 0x1", response[0], response[1]); return FALSE; } /* Compare flags: */ /* Response type */ if ((response[2] & 0x80) != 0x80) { socket_setError(socket, "DNS: invalid response type: 0x%x", response[2] & 0x80); return FALSE; } /* Response code: accept request refusal as correct response as the server may disallow NS root query but the negative response means, it reacts to requests */ rc = response[3] & 0x0F; if (rc != 0x0 && rc != 0x5) { socket_setError(socket, "DNS: invalid response code: 0x%x", rc); return FALSE; } /* Compare queries count (it should be one as in our request): */ if (response[4] != 0x00 && response[5] != 0x01) { socket_setError(socket, "DNS: invalid query count in response -- received 0x%x%x, expected 1", response[4], response[5]); return FALSE; } /* Compare answer and authority resource record counts (they shouldn't be both zero) */ if (rc == 0 && response[6] == 0x00 && response[7] == 0x00 && response[8] == 0x00 && response[9] == 0x00) { socket_setError(socket, "DNS: no answer or authority records returned"); return FALSE; } return TRUE; }
int check_sip(Socket_T socket) { int status; char buf[STRLEN]; int port; char *transport; Port_T P; const char *request; const char *myip; char *rport= ""; char *proto; ASSERT(socket); P= socket_get_Port(socket); ASSERT(P); request= P->request?P->request:"*****@*****.**"; port = socket_get_local_port(socket); proto = socket_is_secure(socket) ? "sips" : "sip"; switch(socket_get_type(socket)) { case SOCK_DGRAM: { transport="UDP"; rport=";rport"; break; } case SOCK_STREAM: { transport="TCP"; break; } default: { socket_setError(socket, "Unsupported socket type, only TCP and UDP are supported\n"); return TRUE; } } myip= socket_get_local_host(socket); if(socket_print(socket, "OPTIONS %s:%s SIP/2.0\r\n" "Via: SIP/2.0/%s %s:%d;branch=z9hG4bKh%u%s\r\n" "Max-Forwards: %d\r\n" "To: <%s:%s>\r\n" "From: monit <%s:monit@%s>;tag=%d\r\n" "Call-ID: %u\r\n" "CSeq: 63104 OPTIONS\r\n" "Contact: <%s:%s:%d>\r\n" "Accept: application/sdp\r\n" "Content-Length: 0\r\n" "User-Agent: %s/%s\r\n\r\n", proto, // protocol request, // to transport, // via transport udp|tcp myip, // who its from port, // our port random(), // branch rport, // rport option P->maxforward, // maximum forwards proto, // protocol request, // to proto, // protocol myip, // from host random(), // tag random(), // call id proto, // protocol myip, // contact host port, // contact port prog, VERSION // user agent ) < 0) { socket_setError(socket, "SIP: error sending data -- %s\n", STRERROR); return FALSE; } if(! socket_readln(socket, buf, sizeof(buf))) { socket_setError(socket, "SIP: error receiving data -- %s\n", STRERROR); return FALSE; } Str_chomp(buf); DEBUG("Response from SIP server: %s\n", buf); if(! sscanf(buf, "%*s %d", &status)) { socket_setError(socket, "SIP error: cannot parse SIP status in response: %s\n", buf); return FALSE; } if(status >= 400) { socket_setError(socket, "SIP error: Server returned status %d\n", status); return FALSE; } if(status >= 300 && status < 400) { socket_setError(socket, "SIP info: Server redirection. Returned status %d\n", status); return FALSE; } if(status > 100 && status < 200) { socket_setError(socket, "SIP error: Provisional response . Returned status %d\n", status); return FALSE; } return TRUE; }
/** * Simple RADIUS test. * * We send a Status-Server packet, and expect an Access-Accept or Accounting-Response packet. * * */ int check_radius(Socket_T socket) { int i, length, left; int secret_len; Port_T P; md5_context_t ctx; char *secret; unsigned char *attr; unsigned char digest[16]; unsigned char response[STRLEN]; unsigned char request[38] = { /* Status-Server */ 0x0c, /* Code, we always use zero */ 0x00, /* Packet length */ 0x00, 0x26, /* Request Authenticator */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Message-Authenticator */ 0x50, /* Length */ 0x12, /* Contents of Message-Authenticator */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; ASSERT(socket); if (socket_get_type(socket) != SOCK_DGRAM) { socket_setError(socket, "RADIUS: unsupported socket type -- protocol test skipped\n"); return TRUE; } P = socket_get_Port(socket); ASSERT(P); secret = P->request ? P->request : "testing123"; secret_len = (int)strlen(secret); /* get 16 bytes of random data */ for (i = 0; i < 16; i++) request[i + 4] = ((unsigned int)random()) & 0xff; /* sign the packet */ Util_hmacMD5(request, sizeof(request), (unsigned char *)secret, secret_len, request + 22); if (socket_write(socket, (unsigned char *)request, sizeof(request)) < 0) { socket_setError(socket, "RADIUS: error sending query -- %s\n", STRERROR); return FALSE; } /* the response should have at least 20 bytes */ if ((length = socket_read(socket, (unsigned char *)response, sizeof(response))) < 20) { socket_setError(socket, "RADIUS: error receiving response -- %s\n", STRERROR); return FALSE; } /* compare the response code (should be Access-Accept or Accounting-Response) */ if ((response[0] != 2) && (response[0] != 5)) { socket_setError(socket, "RADIUS: Invalid reply code -- error occured\n"); return FALSE; } /* compare the packet ID (it should be the same as in our request) */ if (response[1] != 0x00) { socket_setError(socket, "RADIUS: ID mismatch\n"); return FALSE; } /* check the length */ if (response[2] != 0) { socket_setError(socket, "RADIUS: message is too long\n"); return FALSE; } /* check length against packet data */ if (response[3] != length) { socket_setError(socket, "RADIUS: message has invalid length\n"); return FALSE; } /* validate that it is a well-formed packet */ attr = response + 20; left = length - 20; while (left > 0) { if (left < 2) { socket_setError(socket, "RADIUS: message is malformed\n"); return FALSE; } if (attr[1] < 2) { socket_setError(socket, "RADIUS: message has invalid attribute length\n"); return FALSE; } if (attr[1] > left) { socket_setError(socket, "RADIUS: message has attribute that is too long\n"); return FALSE; } /* validate Message-Authenticator, if found */ if (attr[0] == 0x50) { /* FIXME: validate it */ } left -= attr[1]; } /* save the reply authenticator, and copy the request authenticator over */ memcpy(digest, response + 4, 16); memcpy(response + 4, request + 4, 16); md5_init(&ctx); md5_append(&ctx, (const md5_byte_t *)response, length); md5_append(&ctx, (const md5_byte_t *)secret, secret_len); md5_finish(&ctx, response + 4); if (memcmp(digest, response + 4, 16) != 0) socket_setError(socket, "RADIUS: message fails authentication\n"); return TRUE; }