|
Packit Service |
4684c1 |
/*
|
|
Packit Service |
4684c1 |
* Copyright (C) 2000-2016 Free Software Foundation, Inc.
|
|
Packit Service |
4684c1 |
* Copyright (C) 2015-2016 Red Hat, Inc.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* This file is part of GnuTLS.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* GnuTLS is free software: you can redistribute it and/or modify
|
|
Packit Service |
4684c1 |
* it under the terms of the GNU General Public License as published by
|
|
Packit Service |
4684c1 |
* the Free Software Foundation, either version 3 of the License, or
|
|
Packit Service |
4684c1 |
* (at your option) any later version.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* GnuTLS is distributed in the hope that it will be useful,
|
|
Packit Service |
4684c1 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
4684c1 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit Service |
4684c1 |
* GNU General Public License for more details.
|
|
Packit Service |
4684c1 |
*
|
|
Packit Service |
4684c1 |
* You should have received a copy of the GNU General Public License
|
|
Packit Service |
4684c1 |
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#include <config.h>
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#if HAVE_SYS_SOCKET_H
|
|
Packit Service |
4684c1 |
#include <sys/socket.h>
|
|
Packit Service |
4684c1 |
#elif HAVE_WS2TCPIP_H
|
|
Packit Service |
4684c1 |
#include <ws2tcpip.h>
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
#include <netdb.h>
|
|
Packit Service |
4684c1 |
#include <string.h>
|
|
Packit Service |
4684c1 |
#include <errno.h>
|
|
Packit Service |
4684c1 |
#include <sys/select.h>
|
|
Packit Service |
4684c1 |
#include <sys/types.h>
|
|
Packit Service |
4684c1 |
#include <stdio.h>
|
|
Packit Service |
4684c1 |
#include <stdlib.h>
|
|
Packit Service |
4684c1 |
#include <unistd.h>
|
|
Packit Service |
4684c1 |
#include <arpa/inet.h>
|
|
Packit Service |
4684c1 |
#include <socket.h>
|
|
Packit Service |
4684c1 |
#include <c-ctype.h>
|
|
Packit Service |
4684c1 |
#include "sockets.h"
|
|
Packit Service |
4684c1 |
#include "common.h"
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#ifdef _WIN32
|
|
Packit Service |
4684c1 |
# undef endservent
|
|
Packit Service |
4684c1 |
# define endservent()
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#define MAX_BUF 4096
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* Functions to manipulate sockets
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ssize_t
|
|
Packit Service |
4684c1 |
socket_recv(const socket_st * socket, void *buffer, int buffer_size)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
int ret;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (socket->secure) {
|
|
Packit Service |
4684c1 |
do {
|
|
Packit Service |
4684c1 |
ret =
|
|
Packit Service |
4684c1 |
gnutls_record_recv(socket->session, buffer,
|
|
Packit Service |
4684c1 |
buffer_size);
|
|
Packit Service |
4684c1 |
if (ret == GNUTLS_E_HEARTBEAT_PING_RECEIVED)
|
|
Packit Service |
4684c1 |
gnutls_heartbeat_pong(socket->session, 0);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
while (ret == GNUTLS_E_INTERRUPTED
|
|
Packit Service |
4684c1 |
|| ret == GNUTLS_E_HEARTBEAT_PING_RECEIVED);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
} else
|
|
Packit Service |
4684c1 |
do {
|
|
Packit Service |
4684c1 |
ret = recv(socket->fd, buffer, buffer_size, 0);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
while (ret == -1 && errno == EINTR);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return ret;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ssize_t
|
|
Packit Service |
4684c1 |
socket_recv_timeout(const socket_st * socket, void *buffer, int buffer_size, unsigned ms)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
int ret;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (socket->secure)
|
|
Packit Service |
4684c1 |
gnutls_record_set_timeout(socket->session, ms);
|
|
Packit Service |
4684c1 |
ret = socket_recv(socket, buffer, buffer_size);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (socket->secure)
|
|
Packit Service |
4684c1 |
gnutls_record_set_timeout(socket->session, 0);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return ret;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ssize_t
|
|
Packit Service |
4684c1 |
socket_send(const socket_st * socket, const void *buffer, int buffer_size)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
return socket_send_range(socket, buffer, buffer_size, NULL);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ssize_t
|
|
Packit Service |
4684c1 |
socket_send_range(const socket_st * socket, const void *buffer,
|
|
Packit Service |
4684c1 |
int buffer_size, gnutls_range_st * range)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
int ret;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (socket->secure)
|
|
Packit Service |
4684c1 |
do {
|
|
Packit Service |
4684c1 |
if (range == NULL)
|
|
Packit Service |
4684c1 |
ret =
|
|
Packit Service |
4684c1 |
gnutls_record_send(socket->session,
|
|
Packit Service |
4684c1 |
buffer,
|
|
Packit Service |
4684c1 |
buffer_size);
|
|
Packit Service |
4684c1 |
else
|
|
Packit Service |
4684c1 |
ret =
|
|
Packit Service |
4684c1 |
gnutls_record_send_range(socket->
|
|
Packit Service |
4684c1 |
session,
|
|
Packit Service |
4684c1 |
buffer,
|
|
Packit Service |
4684c1 |
buffer_size,
|
|
Packit Service |
4684c1 |
range);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
while (ret == GNUTLS_E_AGAIN
|
|
Packit Service |
4684c1 |
|| ret == GNUTLS_E_INTERRUPTED);
|
|
Packit Service |
4684c1 |
else
|
|
Packit Service |
4684c1 |
do {
|
|
Packit Service |
4684c1 |
ret = send(socket->fd, buffer, buffer_size, 0);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
while (ret == -1 && errno == EINTR);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (ret > 0 && ret != buffer_size && socket->verbose)
|
|
Packit Service |
4684c1 |
fprintf(stderr,
|
|
Packit Service |
4684c1 |
"*** Only sent %d bytes instead of %d.\n", ret,
|
|
Packit Service |
4684c1 |
buffer_size);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return ret;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static
|
|
Packit Service |
4684c1 |
ssize_t send_line(socket_st * socket, const char *txt)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
int len = strlen(txt);
|
|
Packit Service |
4684c1 |
int ret;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (socket->verbose)
|
|
Packit Service |
4684c1 |
fprintf(stderr, "starttls: sending: %s\n", txt);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = send(socket->fd, txt, len, 0);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (ret == -1) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "error sending \"%s\"\n", txt);
|
|
Packit Service |
4684c1 |
exit(2);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return ret;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static
|
|
Packit Service |
4684c1 |
ssize_t wait_for_text(socket_st * socket, const char *txt, unsigned txt_size)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
char buf[1024];
|
|
Packit Service |
4684c1 |
char *pbuf, *p;
|
|
Packit Service |
4684c1 |
int ret;
|
|
Packit Service |
4684c1 |
fd_set read_fds;
|
|
Packit Service |
4684c1 |
struct timeval tv;
|
|
Packit Service |
4684c1 |
size_t left, got;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (txt_size > sizeof(buf))
|
|
Packit Service |
4684c1 |
abort();
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (socket->verbose && txt != NULL)
|
|
Packit Service |
4684c1 |
fprintf(stderr, "starttls: waiting for: \"%.*s\"\n", txt_size, txt);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
pbuf = buf;
|
|
Packit Service |
4684c1 |
left = sizeof(buf)-1;
|
|
Packit Service |
4684c1 |
got = 0;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
do {
|
|
Packit Service |
4684c1 |
FD_ZERO(&read_fds);
|
|
Packit Service |
4684c1 |
FD_SET(socket->fd, &read_fds);
|
|
Packit Service |
4684c1 |
tv.tv_sec = 10;
|
|
Packit Service |
4684c1 |
tv.tv_usec = 0;
|
|
Packit Service |
4684c1 |
ret = select(socket->fd + 1, &read_fds, NULL, NULL, &tv;;
|
|
Packit Service |
4684c1 |
if (ret > 0)
|
|
Packit Service |
4684c1 |
ret = recv(socket->fd, pbuf, left, 0);
|
|
Packit Service |
4684c1 |
if (ret == -1) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "error receiving '%s': %s\n", txt, strerror(errno));
|
|
Packit Service |
4684c1 |
exit(2);
|
|
Packit Service |
4684c1 |
} else if (ret == 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "error receiving '%s': Timeout\n", txt);
|
|
Packit Service |
4684c1 |
exit(2);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
pbuf[ret] = 0;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (txt == NULL)
|
|
Packit Service |
4684c1 |
break;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (socket->verbose)
|
|
Packit Service |
4684c1 |
fprintf(stderr, "starttls: received: %s\n", pbuf);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
pbuf += ret;
|
|
Packit Service |
4684c1 |
left -= ret;
|
|
Packit Service |
4684c1 |
got += ret;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* check for text after a newline in buffer */
|
|
Packit Service |
4684c1 |
if (got > txt_size) {
|
|
Packit Service |
4684c1 |
p = memmem(buf, got, txt, txt_size);
|
|
Packit Service |
4684c1 |
if (p != NULL && p != buf) {
|
|
Packit Service |
4684c1 |
p--;
|
|
Packit Service |
4684c1 |
if (*p == '\n' || *p == '\r' || (*txt == '<' && *p == '>')) // XMPP is not line oriented, uses XML format
|
|
Packit Service |
4684c1 |
break;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
} while(got < txt_size || strncmp(buf, txt, txt_size) != 0);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return got;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static void
|
|
Packit Service |
4684c1 |
socket_starttls(socket_st * socket)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
char buf[512];
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (socket->secure)
|
|
Packit Service |
4684c1 |
return;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (socket->app_proto == NULL || strcasecmp(socket->app_proto, "https") == 0)
|
|
Packit Service |
4684c1 |
return;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (strcasecmp(socket->app_proto, "smtp") == 0 || strcasecmp(socket->app_proto, "submission") == 0) {
|
|
Packit Service |
4684c1 |
if (socket->verbose)
|
|
Packit Service |
4684c1 |
log_msg(stdout, "Negotiating SMTP STARTTLS\n");
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
wait_for_text(socket, "220 ", 4);
|
|
Packit Service |
4684c1 |
snprintf(buf, sizeof(buf), "EHLO %s\r\n", socket->hostname);
|
|
Packit Service |
4684c1 |
send_line(socket, buf);
|
|
Packit Service |
4684c1 |
wait_for_text(socket, "250 ", 4);
|
|
Packit Service |
4684c1 |
send_line(socket, "STARTTLS\r\n");
|
|
Packit Service |
4684c1 |
wait_for_text(socket, "220 ", 4);
|
|
Packit Service |
4684c1 |
} else if (strcasecmp(socket->app_proto, "imap") == 0 || strcasecmp(socket->app_proto, "imap2") == 0) {
|
|
Packit Service |
4684c1 |
if (socket->verbose)
|
|
Packit Service |
4684c1 |
log_msg(stdout, "Negotiating IMAP STARTTLS\n");
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
send_line(socket, "a CAPABILITY\r\n");
|
|
Packit Service |
4684c1 |
wait_for_text(socket, "a OK", 4);
|
|
Packit Service |
4684c1 |
send_line(socket, "a STARTTLS\r\n");
|
|
Packit Service |
4684c1 |
wait_for_text(socket, "a OK", 4);
|
|
Packit Service |
4684c1 |
} else if (strcasecmp(socket->app_proto, "xmpp") == 0) {
|
|
Packit Service |
4684c1 |
if (socket->verbose)
|
|
Packit Service |
4684c1 |
log_msg(stdout, "Negotiating XMPP STARTTLS\n");
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
snprintf(buf, sizeof(buf), "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:client' to='%s' version='1.0'>\n", socket->hostname);
|
|
Packit Service |
4684c1 |
send_line(socket, buf);
|
|
Packit Service |
4684c1 |
wait_for_text(socket, "
|
|
Packit Service |
4684c1 |
send_line(socket, "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>");
|
|
Packit Service |
4684c1 |
wait_for_text(socket, "
|
|
Packit Service |
4684c1 |
} else if (strcasecmp(socket->app_proto, "ldap") == 0) {
|
|
Packit Service |
4684c1 |
if (socket->verbose)
|
|
Packit Service |
4684c1 |
log_msg(stdout, "Negotiating LDAP STARTTLS\n");
|
|
Packit Service |
4684c1 |
#define LDAP_STR "\x30\x1d\x02\x01\x01\x77\x18\x80\x16\x31\x2e\x33\x2e\x36\x2e\x31\x2e\x34\x2e\x31\x2e\x31\x34\x36\x36\x2e\x32\x30\x30\x33\x37"
|
|
Packit Service |
4684c1 |
send(socket->fd, LDAP_STR, sizeof(LDAP_STR)-1, 0);
|
|
Packit Service |
4684c1 |
wait_for_text(socket, NULL, 0);
|
|
Packit Service |
4684c1 |
} else if (strcasecmp(socket->app_proto, "ftp") == 0 || strcasecmp(socket->app_proto, "ftps") == 0) {
|
|
Packit Service |
4684c1 |
if (socket->verbose)
|
|
Packit Service |
4684c1 |
log_msg(stdout, "Negotiating FTP STARTTLS\n");
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
send_line(socket, "FEAT\r\n");
|
|
Packit Service |
4684c1 |
wait_for_text(socket, "211 ", 4);
|
|
Packit Service |
4684c1 |
send_line(socket, "AUTH TLS\r\n");
|
|
Packit Service |
4684c1 |
wait_for_text(socket, "234", 3);
|
|
Packit Service |
4684c1 |
} else if (strcasecmp(socket->app_proto, "lmtp") == 0) {
|
|
Packit Service |
4684c1 |
if (socket->verbose)
|
|
Packit Service |
4684c1 |
log_msg(stdout, "Negotiating LMTP STARTTLS\n");
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
wait_for_text(socket, "220 ", 4);
|
|
Packit Service |
4684c1 |
snprintf(buf, sizeof(buf), "LHLO %s\r\n", socket->hostname);
|
|
Packit Service |
4684c1 |
send_line(socket, buf);
|
|
Packit Service |
4684c1 |
wait_for_text(socket, "250 ", 4);
|
|
Packit Service |
4684c1 |
send_line(socket, "STARTTLS\r\n");
|
|
Packit Service |
4684c1 |
wait_for_text(socket, "220 ", 4);
|
|
Packit Service |
4684c1 |
} else if (strcasecmp(socket->app_proto, "pop3") == 0) {
|
|
Packit Service |
4684c1 |
if (socket->verbose)
|
|
Packit Service |
4684c1 |
log_msg(stdout, "Negotiating POP3 STARTTLS\n");
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
wait_for_text(socket, "+OK", 3);
|
|
Packit Service |
4684c1 |
send_line(socket, "STLS\r\n");
|
|
Packit Service |
4684c1 |
wait_for_text(socket, "+OK", 3);
|
|
Packit Service |
4684c1 |
} else if (strcasecmp(socket->app_proto, "nntp") == 0) {
|
|
Packit Service |
4684c1 |
if (socket->verbose)
|
|
Packit Service |
4684c1 |
log_msg(stdout, "Negotiating NNTP STARTTLS\n");
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
wait_for_text(socket, "200 ", 4);
|
|
Packit Service |
4684c1 |
send_line(socket, "STARTTLS\r\n");
|
|
Packit Service |
4684c1 |
wait_for_text(socket, "382 ", 4);
|
|
Packit Service |
4684c1 |
} else if (strcasecmp(socket->app_proto, "sieve") == 0) {
|
|
Packit Service |
4684c1 |
if (socket->verbose)
|
|
Packit Service |
4684c1 |
log_msg(stdout, "Negotiating Sieve STARTTLS\n");
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
wait_for_text(socket, "OK ", 3);
|
|
Packit Service |
4684c1 |
send_line(socket, "STARTTLS\r\n");
|
|
Packit Service |
4684c1 |
wait_for_text(socket, "OK ", 3);
|
|
Packit Service |
4684c1 |
} else if (strcasecmp(socket->app_proto, "postgres") == 0 || strcasecmp(socket->app_proto, "postgresql") == 0) {
|
|
Packit Service |
4684c1 |
if (socket->verbose)
|
|
Packit Service |
4684c1 |
log_msg(stdout, "Negotiating PostgreSQL STARTTLS\n");
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#define POSTGRES_STR "\x00\x00\x00\x08\x04\xD2\x16\x2F"
|
|
Packit Service |
4684c1 |
send(socket->fd, POSTGRES_STR, sizeof(POSTGRES_STR)-1, 0);
|
|
Packit Service |
4684c1 |
wait_for_text(socket, NULL, 0);
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
if (!c_isdigit(socket->app_proto[0])) {
|
|
Packit Service |
4684c1 |
static int warned = 0;
|
|
Packit Service |
4684c1 |
if (warned == 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "unknown protocol '%s'\n", socket->app_proto);
|
|
Packit Service |
4684c1 |
warned = 1;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
#define CANON_SERVICE(app_proto) \
|
|
Packit Service |
4684c1 |
if (strcasecmp(app_proto, "xmpp") == 0) \
|
|
Packit Service |
4684c1 |
app_proto = "xmpp-server"; \
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
int
|
|
Packit Service |
4684c1 |
starttls_proto_to_port(const char *app_proto)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
struct servent *s;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
CANON_SERVICE(app_proto);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
s = getservbyname(app_proto, NULL);
|
|
Packit Service |
4684c1 |
if (s != NULL) {
|
|
Packit Service |
4684c1 |
return ntohs(s->s_port);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
endservent();
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return 443;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
const char *starttls_proto_to_service(const char *app_proto)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
struct servent *s;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
CANON_SERVICE(app_proto);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
s = getservbyname(app_proto, NULL);
|
|
Packit Service |
4684c1 |
if (s != NULL) {
|
|
Packit Service |
4684c1 |
return s->s_name;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
endservent();
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return "443";
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
void socket_bye(socket_st * socket, unsigned polite)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
int ret;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (socket->secure && socket->session) {
|
|
Packit Service |
4684c1 |
if (polite) {
|
|
Packit Service |
4684c1 |
do
|
|
Packit Service |
4684c1 |
ret = gnutls_bye(socket->session, GNUTLS_SHUT_WR);
|
|
Packit Service |
4684c1 |
while (ret == GNUTLS_E_INTERRUPTED
|
|
Packit Service |
4684c1 |
|| ret == GNUTLS_E_AGAIN);
|
|
Packit Service |
4684c1 |
if (socket->verbose && ret < 0)
|
|
Packit Service |
4684c1 |
fprintf(stderr, "*** gnutls_bye() error: %s\n",
|
|
Packit Service |
4684c1 |
gnutls_strerror(ret));
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (socket->session) {
|
|
Packit Service |
4684c1 |
gnutls_deinit(socket->session);
|
|
Packit Service |
4684c1 |
socket->session = NULL;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
freeaddrinfo(socket->addr_info);
|
|
Packit Service |
4684c1 |
socket->addr_info = socket->ptr = NULL;
|
|
Packit Service |
4684c1 |
socket->connect_addrlen = 0;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
free(socket->ip);
|
|
Packit Service |
4684c1 |
free(socket->hostname);
|
|
Packit Service |
4684c1 |
free(socket->service);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
shutdown(socket->fd, SHUT_RDWR); /* no more receptions */
|
|
Packit Service |
4684c1 |
close(socket->fd);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
gnutls_free(socket->rdata.data);
|
|
Packit Service |
4684c1 |
socket->rdata.data = NULL;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (socket->server_trace)
|
|
Packit Service |
4684c1 |
fclose(socket->server_trace);
|
|
Packit Service |
4684c1 |
if (socket->client_trace)
|
|
Packit Service |
4684c1 |
fclose(socket->client_trace);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
socket->fd = -1;
|
|
Packit Service |
4684c1 |
socket->secure = 0;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* Handle host:port format.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
void canonicalize_host(char *hostname, char *service, unsigned service_size)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
char *p;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if ((p = strchr(hostname, ':'))) {
|
|
Packit Service |
4684c1 |
unsigned char buf[64];
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (inet_pton(AF_INET6, hostname, buf) == 1)
|
|
Packit Service |
4684c1 |
return;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
*p = 0;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (service && service_size)
|
|
Packit Service |
4684c1 |
snprintf(service, service_size, "%s", p+1);
|
|
Packit Service |
4684c1 |
} else
|
|
Packit Service |
4684c1 |
p = hostname + strlen(hostname);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (p > hostname && p[-1] == '.')
|
|
Packit Service |
4684c1 |
p[-1] = 0; // remove trailing dot on FQDN
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static ssize_t
|
|
Packit Service |
4684c1 |
wrap_pull(gnutls_transport_ptr_t ptr, void *data, size_t len)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
socket_st *hd = ptr;
|
|
Packit Service |
4684c1 |
ssize_t r;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
r = recv(hd->fd, data, len, 0);
|
|
Packit Service |
4684c1 |
if (r > 0 && hd->server_trace) {
|
|
Packit Service |
4684c1 |
fwrite(data, 1, r, hd->server_trace);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
return r;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
static ssize_t
|
|
Packit Service |
4684c1 |
wrap_push(gnutls_transport_ptr_t ptr, const void *data, size_t len)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
socket_st *hd = ptr;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (hd->client_trace) {
|
|
Packit Service |
4684c1 |
fwrite(data, 1, len, hd->client_trace);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return send(hd->fd, data, len, 0);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* inline is used to avoid a gcc warning if used in mini-eagain */
|
|
Packit Service |
4684c1 |
inline static int wrap_pull_timeout_func(gnutls_transport_ptr_t ptr,
|
|
Packit Service |
4684c1 |
unsigned int ms)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
socket_st *hd = ptr;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return gnutls_system_recv_timeout((gnutls_transport_ptr_t)(long)hd->fd, ms);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
void
|
|
Packit Service |
4684c1 |
socket_open2(socket_st * hd, const char *hostname, const char *service,
|
|
Packit Service |
4684c1 |
const char *app_proto, int flags, const char *msg, gnutls_datum_t *rdata, gnutls_datum_t *edata,
|
|
Packit Service |
4684c1 |
FILE *server_trace, FILE *client_trace)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
struct addrinfo hints, *res, *ptr;
|
|
Packit Service |
4684c1 |
int sd, err = 0;
|
|
Packit Service |
4684c1 |
int udp = flags & SOCKET_FLAG_UDP;
|
|
Packit Service |
4684c1 |
int ret;
|
|
Packit Service |
4684c1 |
int fastopen = flags & SOCKET_FLAG_FASTOPEN;
|
|
Packit Service |
4684c1 |
char buffer[MAX_BUF + 1];
|
|
Packit Service |
4684c1 |
char portname[16] = { 0 };
|
|
Packit Service |
4684c1 |
gnutls_datum_t idna;
|
|
Packit Service |
4684c1 |
char *a_hostname;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
memset(hd, 0, sizeof(*hd));
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (flags & SOCKET_FLAG_VERBOSE)
|
|
Packit Service |
4684c1 |
hd->verbose = 1;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (rdata) {
|
|
Packit Service |
4684c1 |
hd->rdata.data = rdata->data;
|
|
Packit Service |
4684c1 |
hd->rdata.size = rdata->size;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (edata) {
|
|
Packit Service |
4684c1 |
hd->edata.data = edata->data;
|
|
Packit Service |
4684c1 |
hd->edata.size = edata->size;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
ret = gnutls_idna_map(hostname, strlen(hostname), &idna, 0);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Cannot convert %s to IDNA: %s\n", hostname, gnutls_strerror(ret));
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
hd->hostname = strdup(hostname);
|
|
Packit Service |
4684c1 |
a_hostname = (char*)idna.data;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (msg != NULL)
|
|
Packit Service |
4684c1 |
log_msg(stdout, "Resolving '%s:%s'...\n", a_hostname, service);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* get server name */
|
|
Packit Service |
4684c1 |
memset(&hints, 0, sizeof(hints));
|
|
Packit Service |
4684c1 |
hints.ai_socktype = udp ? SOCK_DGRAM : SOCK_STREAM;
|
|
Packit Service |
4684c1 |
if ((err = getaddrinfo(a_hostname, service, &hints, &res))) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Cannot resolve %s:%s: %s\n", hostname,
|
|
Packit Service |
4684c1 |
service, gai_strerror(err));
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
sd = -1;
|
|
Packit Service |
4684c1 |
for (ptr = res; ptr != NULL; ptr = ptr->ai_next) {
|
|
Packit Service |
4684c1 |
sd = socket(ptr->ai_family, ptr->ai_socktype,
|
|
Packit Service |
4684c1 |
ptr->ai_protocol);
|
|
Packit Service |
4684c1 |
if (sd == -1)
|
|
Packit Service |
4684c1 |
continue;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if ((err =
|
|
Packit Service |
4684c1 |
getnameinfo(ptr->ai_addr, ptr->ai_addrlen, buffer,
|
|
Packit Service |
4684c1 |
MAX_BUF, portname, sizeof(portname),
|
|
Packit Service |
4684c1 |
NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "getnameinfo(): %s\n",
|
|
Packit Service |
4684c1 |
gai_strerror(err));
|
|
Packit Service |
4684c1 |
continue;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (hints.ai_socktype == SOCK_DGRAM) {
|
|
Packit Service |
4684c1 |
#if defined(IP_DONTFRAG)
|
|
Packit Service |
4684c1 |
int yes = 1;
|
|
Packit Service |
4684c1 |
if (setsockopt(sd, IPPROTO_IP, IP_DONTFRAG,
|
|
Packit Service |
4684c1 |
(const void *) &yes,
|
|
Packit Service |
4684c1 |
sizeof(yes)) < 0)
|
|
Packit Service |
4684c1 |
perror("setsockopt(IP_DF) failed");
|
|
Packit Service |
4684c1 |
#elif defined(IP_MTU_DISCOVER)
|
|
Packit Service |
4684c1 |
int yes = IP_PMTUDISC_DO;
|
|
Packit Service |
4684c1 |
if (setsockopt(sd, IPPROTO_IP, IP_MTU_DISCOVER,
|
|
Packit Service |
4684c1 |
(const void *) &yes,
|
|
Packit Service |
4684c1 |
sizeof(yes)) < 0)
|
|
Packit Service |
4684c1 |
perror("setsockopt(IP_DF) failed");
|
|
Packit Service |
4684c1 |
#endif
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (fastopen && ptr->ai_socktype == SOCK_STREAM
|
|
Packit Service |
4684c1 |
&& (ptr->ai_family == AF_INET || ptr->ai_family == AF_INET6)) {
|
|
Packit Service |
4684c1 |
memcpy(&hd->connect_addr, ptr->ai_addr, ptr->ai_addrlen);
|
|
Packit Service |
4684c1 |
hd->connect_addrlen = ptr->ai_addrlen;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (msg)
|
|
Packit Service |
4684c1 |
log_msg(stdout, "%s '%s:%s' (TFO)...\n", msg, buffer, portname);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
} else {
|
|
Packit Service |
4684c1 |
if (msg)
|
|
Packit Service |
4684c1 |
log_msg(stdout, "%s '%s:%s'...\n", msg, buffer, portname);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if ((err = connect(sd, ptr->ai_addr, ptr->ai_addrlen)) < 0)
|
|
Packit Service |
4684c1 |
continue;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
hd->fd = sd;
|
|
Packit Service |
4684c1 |
if (flags & SOCKET_FLAG_STARTTLS) {
|
|
Packit Service |
4684c1 |
hd->app_proto = app_proto;
|
|
Packit Service |
4684c1 |
socket_starttls(hd);
|
|
Packit Service |
4684c1 |
hd->app_proto = NULL;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (!(flags & SOCKET_FLAG_SKIP_INIT)) {
|
|
Packit Service |
4684c1 |
hd->session = init_tls_session(hostname);
|
|
Packit Service |
4684c1 |
if (hd->session == NULL) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "error initializing session\n");
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (hd->session) {
|
|
Packit Service |
4684c1 |
if (hd->edata.data) {
|
|
Packit Service |
4684c1 |
ret = gnutls_record_send_early_data(hd->session, hd->edata.data, hd->edata.size);
|
|
Packit Service |
4684c1 |
if (ret < 0) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "error sending early data\n");
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
if (hd->rdata.data) {
|
|
Packit Service |
4684c1 |
gnutls_session_set_data(hd->session, hd->rdata.data, hd->rdata.size);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (server_trace)
|
|
Packit Service |
4684c1 |
hd->server_trace = server_trace;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (client_trace)
|
|
Packit Service |
4684c1 |
hd->client_trace = client_trace;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
gnutls_transport_set_push_function(hd->session, wrap_push);
|
|
Packit Service |
4684c1 |
gnutls_transport_set_pull_function(hd->session, wrap_pull);
|
|
Packit Service |
4684c1 |
gnutls_transport_set_pull_timeout_function(hd->session, wrap_pull_timeout_func);
|
|
Packit Service |
4684c1 |
gnutls_transport_set_ptr(hd->session, hd);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (!(flags & SOCKET_FLAG_RAW) && !(flags & SOCKET_FLAG_SKIP_INIT)) {
|
|
Packit Service |
4684c1 |
err = do_handshake(hd);
|
|
Packit Service |
4684c1 |
if (err == GNUTLS_E_PUSH_ERROR) { /* failed connecting */
|
|
Packit Service |
4684c1 |
gnutls_deinit(hd->session);
|
|
Packit Service |
4684c1 |
hd->session = NULL;
|
|
Packit Service |
4684c1 |
continue;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
else if (err < 0) {
|
|
Packit Service |
4684c1 |
if (!(flags & SOCKET_FLAG_DONT_PRINT_ERRORS))
|
|
Packit Service |
4684c1 |
fprintf(stderr, "*** handshake has failed: %s\n", gnutls_strerror(err));
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
break;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (err != 0) {
|
|
Packit Service |
4684c1 |
int e = errno;
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Could not connect to %s:%s: %s\n",
|
|
Packit Service |
4684c1 |
buffer, portname, strerror(e));
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (sd == -1) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Could not find a supported socket\n");
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if ((flags & SOCKET_FLAG_RAW) || (flags & SOCKET_FLAG_SKIP_INIT))
|
|
Packit Service |
4684c1 |
hd->secure = 0;
|
|
Packit Service |
4684c1 |
else
|
|
Packit Service |
4684c1 |
hd->secure = 1;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
hd->fd = sd;
|
|
Packit Service |
4684c1 |
hd->ip = strdup(buffer);
|
|
Packit Service |
4684c1 |
hd->service = strdup(portname);
|
|
Packit Service |
4684c1 |
hd->ptr = ptr;
|
|
Packit Service |
4684c1 |
hd->addr_info = res;
|
|
Packit Service |
4684c1 |
gnutls_free(hd->rdata.data);
|
|
Packit Service |
4684c1 |
hd->rdata.data = NULL;
|
|
Packit Service |
4684c1 |
gnutls_free(hd->edata.data);
|
|
Packit Service |
4684c1 |
hd->edata.data = NULL;
|
|
Packit Service |
4684c1 |
gnutls_free(idna.data);
|
|
Packit Service |
4684c1 |
return;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
/* converts a textual service or port to
|
|
Packit Service |
4684c1 |
* a service.
|
|
Packit Service |
4684c1 |
*/
|
|
Packit Service |
4684c1 |
const char *port_to_service(const char *sport, const char *proto)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
unsigned int port;
|
|
Packit Service |
4684c1 |
struct servent *sr;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
if (!c_isdigit(sport[0]))
|
|
Packit Service |
4684c1 |
return sport;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
port = atoi(sport);
|
|
Packit Service |
4684c1 |
if (port == 0)
|
|
Packit Service |
4684c1 |
return sport;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
port = htons(port);
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
sr = getservbyport(port, proto);
|
|
Packit Service |
4684c1 |
if (sr == NULL) {
|
|
Packit Service |
4684c1 |
fprintf(stderr,
|
|
Packit Service |
4684c1 |
"Warning: getservbyport(%s) failed. Using port number as service.\n", sport);
|
|
Packit Service |
4684c1 |
return sport;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return sr->s_name;
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
int service_to_port(const char *service, const char *proto)
|
|
Packit Service |
4684c1 |
{
|
|
Packit Service |
4684c1 |
unsigned int port;
|
|
Packit Service |
4684c1 |
struct servent *sr;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
port = atoi(service);
|
|
Packit Service |
4684c1 |
if (port != 0)
|
|
Packit Service |
4684c1 |
return port;
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
sr = getservbyname(service, proto);
|
|
Packit Service |
4684c1 |
if (sr == NULL) {
|
|
Packit Service |
4684c1 |
fprintf(stderr, "Warning: getservbyname() failed for '%s/%s'.\n", service, proto);
|
|
Packit Service |
4684c1 |
exit(1);
|
|
Packit Service |
4684c1 |
}
|
|
Packit Service |
4684c1 |
|
|
Packit Service |
4684c1 |
return ntohs(sr->s_port);
|
|
Packit Service |
4684c1 |
}
|