Beispiel #1
0
/**
 * 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)));
  }
      
}
Beispiel #2
0
/**
 *  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;
}
Beispiel #3
0
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;

}
Beispiel #4
0
/**
 *  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;
}