⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dnet.c

📁 This is a implementation of cmd line mode email client. It support ESMTP. I am sure you are able to
💻 C
字号:
#include <stdio.h>#include <unistd.h>#include <string.h>#include <errno.h>#include <assert.h>#include <sys/utsname.h>#include <sys/socket.h>#include <sys/types.h>#include <netinet/in.h>#include <arpa/inet.h>#if HAVE_CONFIG_H#include "config.h"#endif#ifdef HAVE_LIBSSL#include <openssl/ssl.h>#include <openssl/crypto.h>#include <openssl/x509.h>#include <openssl/pem.h>#include <openssl/rand.h>#endif#include "dutil.h"#include "dnet.h"typedef struct sockaddr SA;typedef struct sockaddr_in SIN;struct socket {	bool eom;		/* End of Message? */	int sock;		/* Socket descriptor */	int flags;		/* Error flags */	int errnum;		/* Essentially, errno */	int avail_bytes;	/* Available bytes in buffer */	char *bufptr;		/* Pointer to Internal buffer */	char *buf;		/* The buffer. */#ifdef HAVE_LIBSSL	SSL_CTX *ctx;		/* OpenSSL CTX struct, used for TLS */	SSL *ssl;		/* OpenSSL SSL struct, used for TLS */#endif};/** * A wrapper for gethostbyname. This allows us to figure out * if we need to use the regular gethostbyname, the reentrant * gethostbyname's or an IPV6 version. * * Params * 	name - The hostname to resolve * 	hent - A hostent struct. * * Return * 	ERROR upon failure to resolve name * 	SUCCESS otherwise */intdnetResolveName(const char *name, struct hostent *hent){        int ret = ERROR;         struct hostent *him;        him = gethostbyname(name);        if (him) {                memcpy(hent, him, sizeof(struct hostent));                ret = SUCCESS;        }        return ret;}/** * This function creates a socket connection based on a  * hostname and port.  It will return a FILE descriptor * so that you can perform buffered read/writes on the socket. * * LIMITATIONS * 	- Only opens a PF_INET socket. * 	- "hostname" must be a FQD or ascii IP address. * * Params * 	hostname - The FQD or IP of the host to connect to * 	port - the port to connect on. * * Return * 	dsocket - upon successful connection. * 	NULL - upon failure to connect. */dsocket *dnetConnect(const char *hostname, unsigned int port){	int sd=0;	SIN sin;	struct hostent him;	dsocket *ret = NULL;	memset(&sin, 0, sizeof(SIN));	memset(&him, 0, sizeof(struct hostent));	if (dnetResolveName(hostname, &him) == ERROR) {		return NULL;	}	sin.sin_family = PF_INET;	sin.sin_port = htons(port);	memcpy(&sin.sin_addr.s_addr, him.h_addr_list[0], 		sizeof(sin.sin_addr.s_addr));	sd = socket(sin.sin_family, SOCK_STREAM, 0);	if (sd > 0) {		if (connect(sd, (SA *)&sin, sizeof(SIN)) >= 0) {			ret = xmalloc(sizeof(struct socket));			ret->sock = sd;			ret->buf = xmalloc(MAXSOCKBUF);			ret->bufptr = ret->buf;		}	}	return ret;}/** * Generates a random seed used for TLS connection. */#ifdef HAVE_LIBSSLstatic void_genRandomSeed(void){	struct {		struct utsname uname;		int uname_1;		int uname_2;		uid_t uid;		uid_t euid;		gid_t gid;		gid_t egid;	} data;	struct {		pid_t pid;		time_t time;		void *stack;	} uniq;	data.uname_1 = uname(&data.uname);	data.uname_2 = errno;	data.uid = getuid();	data.euid = geteuid();	data.gid = getgid();	data.egid = getegid();	RAND_seed(&data, sizeof(data));	uniq.pid = getpid();	uniq.time = time(NULL);	uniq.stack = &uniq;	RAND_seed(&uniq, sizeof(uniq));}#endif/** * This will allow you to use TLS over an existing connection. * Will return error if a connection has not already been established. */intdnetUseTls(dsocket *sd){#ifdef HAVE_LIBSSL	// Can't do this unless we have a connection.	if (sd->sock <= 0) {		return ERROR;	}	SSL_load_error_strings();	if (SSL_library_init() == -1) {		return ERROR;	}	_genRandomSeed();	sd->ctx = SSL_CTX_new(TLSv1_client_method());	if (!sd->ctx) {		return ERROR;	}	sd->ssl = SSL_new(sd->ctx);	if (!sd->ssl) {		SSL_CTX_free(sd->ctx);		sd->ctx = NULL;		return ERROR;	}	SSL_set_fd(sd->ssl, sd->sock);	if (SSL_connect(sd->ssl) == -1) {		SSL_CTX_free(sd->ctx);		SSL_free(sd->ssl);		sd->ssl = NULL;		sd->ctx = NULL;		return ERROR;	}#else	sd = sd;#endif	return SUCCESS;}/** * Simply verfies that the certificate of the peer is valid and * that nobody is trying to fool us. */intdnetVerifyCert(dsocket *sd){#ifdef HAVE_LIBSSL	X509 *cert = NULL;	cert = SSL_get_peer_certificate(sd->ssl);	if (!cert) {		return ERROR;	}	/* TODO: Do some sort of verification here. */	X509_free(cert);#else	sd = sd;#endif	return SUCCESS;}/** * Close the socket connection and destroy the SOCKET structure */voiddnetClose(dsocket *sd){	if (sd) {		if (sd->sock) {			close(sd->sock);		}#ifdef HAVE_LIBSSL		if (sd->ssl) {			SSL_shutdown(sd->ssl);			SSL_free(sd->ssl);			if (sd->ctx) {				SSL_CTX_free(sd->ctx);			}		}#endif		if (sd->buf) {			xfree(sd->buf);		}		xfree(sd);	}}/** * This function will be similar to fgetc except it will * use the SOCKET structure for buffering.    It will read * up to sizeof(sd->buf) bytes into the internal buffer * and then let sd->bufptr point to it.    If bufptr is  * not NULL, then it will return a byte each time it is * called and advance the pointer for the next call. If * bufptr is NULL, it will read another sizeof(sd->buf) * bytes and reset sd->bufptr. */intdnetGetc(dsocket *sd){	int retval=1, recval=0;	assert(sd != NULL);	/* If there aren't any bytes available, get some. */	if (sd->avail_bytes <= 0) {		sd->eom = false;		sd->flags = 0;		memset(sd->buf, '\0', MAXSOCKBUF);#ifdef HAVE_LIBSSL		if (!sd->ssl) {#endif			recval = recv(sd->sock, sd->buf, MAXSOCKBUF-1, 0);#ifdef HAVE_LIBSSL		} else {			recval = SSL_read(sd->ssl, sd->buf, MAXSOCKBUF-1);		}#endif		if (recval == 0) {			sd->flags |= SOCKET_EOF;			retval = -1;		} else if (recval == -1) {			sd->flags |= SOCKET_ERROR;			sd->errnum = errno;			retval = -1;		} else {			sd->bufptr = sd->buf;			sd->avail_bytes = recval;			if (recval < MAXSOCKBUF-1) {				// That's all they sent in this message.				sd->eom = true;			} else {				sd->eom = false;			}		}	} 	if (sd->avail_bytes > 0) {		sd->avail_bytes--;		if (sd->avail_bytes == 0 && sd->eom) {			sd->flags |= SOCKET_EOF;		}		retval = *sd->bufptr++;	}	return retval;}/** * This function will be similar to fputc except it will * use the SOCKET struture instead of the FILE structure * to place the file on the stream. */intdnetPutc(dsocket *sd, int ch){	int retval=SUCCESS;	assert(sd != NULL);#ifdef HAVE_LIBSSL	if (!sd->ssl) {#endif		if (send(sd->sock, (char *)&ch, 1, 0) != 1) {			sd->flags |= SOCKET_ERROR;			sd->errnum = errno;			retval = ERROR;		}#ifdef HAVE_LIBSSL	} else {		if (SSL_write(sd->ssl, (char *)&ch, 1) == -1) {			sd->flags |= SOCKET_ERROR;			sd->errnum = errno;			retval = ERROR;		}	}#endif	return retval;}/** * This function will be similar to fgets except it will * use the Sgetc to read one character at a time. */intdnetReadline(dsocket *sd, dstrbuf *buf){	int ch, size=0;	do {		ch = dnetGetc(sd);		if (ch == -1) {			// Error			break;		} else {			dsbCatChar(buf, ch);			size++;		}	} while (ch != '\n' && !dnetEof(sd));	return size;}/** * Writes to a socket */intdnetWrite(dsocket *sd, const char *buf, size_t len){	int bytes = 0;	const size_t blocklen = 4356;	size_t sentLen=0;#ifdef HAVE_LIBSSL	if (!sd->ssl) {#endif		while (len > 0) {			size_t sendSize = (len > blocklen) ? blocklen : len;			bytes = send(sd->sock, buf, sendSize, 0);			if (bytes == -1) {				if (errno == EAGAIN) {					continue;				} else if (errno == EINTR) {					continue;				} else {					sd->flags |= SOCKET_ERROR;					sd->errnum = errno;					break;				}			} else if (bytes == 0) {				sd->flags |= SOCKET_ERROR;				sd->errnum = EPIPE;				break;			} else if (bytes > 0) {				buf += bytes;				len -= bytes;				sentLen += bytes;			}		}#ifdef HAVE_LIBSSL	} else {		sentLen = SSL_write(sd->ssl, buf, len);	}#endif	return sentLen;}/** * Reads stuff from the socket up to size. */intdnetRead(dsocket *sd, char *buf, size_t size){	u_int i;	int ch;	for (i = 0; i < size-1; i++) {		ch = dnetGetc(sd);		if (ch == -1) {			i = 0;			break;		}		*buf++ = ch;		if (dnetEof(sd)) {			break;		}	}	return i;}	/** * Will test the flags for a SOCKET_ERROR  */booldnetErr(dsocket *sd){	return sd->flags & SOCKET_ERROR;}/** * Will test the flags for a SOCKET_EOF */booldnetEof(dsocket *sd){	return sd->flags & SOCKET_EOF;}/** * Returns the error string from the system which is * determined by errnum (errno). */char *dnetGetErr(dsocket *sd){	return strerror(sd->errnum);}intdnetGetSock(dsocket *sd){	return sd->sock;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -