├── examples ├── micbuffer.h ├── ringserver.c ├── http_test.c ├── micclient.c ├── rocksock_test3.c ├── polite_echoserver.c ├── proxychk.c ├── portscanner.c ├── proxychain.c ├── micserver.c └── ssh-socks-restart.c ├── rocksockserver_set_perrorfunc.c ├── .gitignore ├── rocksockserver_set_sleeptime.c ├── rocksockserver_set_signalfd.c ├── rocksock_error.c ├── rocksock_strerror_detailed.c ├── rocksock_dynamic.c ├── rocksock_ssl.c ├── rocksock_internal.h ├── rocksock_strerror_type.c ├── endianness.h ├── rocksock_ssl_internal.h ├── rocksockirc ├── rsirc.h └── rsirc.c ├── rocksockserver.h ├── rocksock_add_proxy.c ├── rocksock_readline.c ├── rocksock_peek.c ├── Makefile ├── rocksock_add_proxy_fromstring.c ├── rocksock_strerror.c ├── rocksock_openssl.c ├── README.md ├── rocksock_cyassl.c ├── configure ├── rocksock.h ├── rocksockserver.c ├── rocksock.c └── COPYING /examples/micbuffer.h: -------------------------------------------------------------------------------- 1 | #define MIC_BUFFER_SIZE 512 2 | #define BITRATE 11025 3 | #define NUMCHANNELS 1 4 | #define FORMAT SND_PCM_FORMAT_U8 5 | 6 | -------------------------------------------------------------------------------- /rocksockserver_set_perrorfunc.c: -------------------------------------------------------------------------------- 1 | #include "rocksockserver.h" 2 | void rocksockserver_set_perrorfunc(rocksockserver* srv, perror_func perr) { 3 | srv->perr = perr; 4 | } 5 | 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | examples/rocksock_test 3 | examples/rocksock_test2 4 | examples/rocksock_test3 5 | *.o 6 | *.lo 7 | *.a 8 | *.so 9 | *.out 10 | *.rcb 11 | config.mak 12 | -------------------------------------------------------------------------------- /rocksockserver_set_sleeptime.c: -------------------------------------------------------------------------------- 1 | #include "rocksockserver.h" 2 | 3 | void rocksockserver_set_sleeptime(rocksockserver* srv, long microsecs) { 4 | srv->sleeptime_us = microsecs; 5 | } 6 | -------------------------------------------------------------------------------- /rocksockserver_set_signalfd.c: -------------------------------------------------------------------------------- 1 | #include "rocksockserver.h" 2 | // pass the reading end of a pipe 3 | void rocksockserver_set_signalfd(rocksockserver* srv, int signalfd) { 4 | srv->signalfd = signalfd; 5 | rocksockserver_watch_fd(srv, signalfd); 6 | } 7 | -------------------------------------------------------------------------------- /rocksock_error.c: -------------------------------------------------------------------------------- 1 | #include "rocksock.h" 2 | 3 | enum rs_errorType rocksock_get_errortype(rocksock *sock) { 4 | return sock->lasterror.errortype; 5 | } 6 | 7 | int rocksock_get_error(rocksock *sock) { 8 | return sock->lasterror.error; 9 | } 10 | 11 | -------------------------------------------------------------------------------- /rocksock_strerror_detailed.c: -------------------------------------------------------------------------------- 1 | #include "rocksock.h" 2 | #include 3 | 4 | char* rocksock_strerror_detailed(rocksock *sock, char *msgbuf, size_t buflen) 5 | { 6 | snprintf(msgbuf, buflen, "%s (proxy %d)", rocksock_strerror(sock), sock->lasterror.failedProxy); 7 | return msgbuf; 8 | } 9 | -------------------------------------------------------------------------------- /rocksock_dynamic.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "rocksock.h" 4 | 5 | 6 | rocksock* rocksock_new(void) { 7 | rocksock* result = calloc(1, sizeof(rocksock)); 8 | return result; 9 | } 10 | 11 | void rocksock_free(rocksock* s) { 12 | if(s) free(s); 13 | } 14 | 15 | -------------------------------------------------------------------------------- /rocksock_ssl.c: -------------------------------------------------------------------------------- 1 | #include "rocksock_ssl_internal.h" 2 | 3 | /* SSL no-op implementation in case rocksock was built without ssl support. 4 | provided so examples/user programs don't need to put ifdefs around their 5 | usage. */ 6 | #ifndef USE_SSL 7 | void rocksock_init_ssl(void) {} 8 | void rocksock_free_ssl(void) {} 9 | #endif 10 | -------------------------------------------------------------------------------- /rocksock_internal.h: -------------------------------------------------------------------------------- 1 | #ifndef ROCKSOCK_INTERNAL_H 2 | #define ROCKSOCK_INTERNAL_H 3 | 4 | #include "rocksock.h" 5 | 6 | typedef struct { 7 | struct addrinfo* hostaddr; 8 | struct addrinfo hostaddr_buf; 9 | struct sockaddr_storage hostaddr_aiaddr_buf; 10 | } rs_resolveStorage; 11 | 12 | int rocksock_seterror(rocksock* sock, rs_errorType errortype, int error, const char* file, int line); 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /rocksock_strerror_type.c: -------------------------------------------------------------------------------- 1 | #include "rocksock.h" 2 | static const char rs_errortype_map[][9] = { 3 | [ RS_ET_OWN ] = "rocksock", 4 | [ RS_ET_SYS ] = "system", 5 | [ RS_ET_GAI ] = "gai/dns", 6 | [ RS_ET_SSL ] = "ssl", 7 | }; 8 | 9 | const char* rocksock_strerror_type(rocksock *sock) { 10 | if(sock->lasterror.errortype < RS_ET_MAX) 11 | return rs_errortype_map[sock->lasterror.errortype]; 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /endianness.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Endianness.h 3 | * 4 | * Created on: 29.11.2010 5 | * 6 | * author: rofl0r 7 | * 8 | * License: LGPL 2.1+ with static linking exception 9 | * 10 | */ 11 | 12 | #ifndef ENDIANNESS_H_ 13 | #define ENDIANNESS_H_ 14 | 15 | #ifdef __linux 16 | #include 17 | #else 18 | #include 19 | #endif 20 | 21 | //#include 22 | //#define IS_BIG_ENDIAN (*(uint16_t *)"\0\xff" < 0x100) 23 | 24 | #if __BYTE_ORDER == __LITTLE_ENDIAN 25 | #define IS_LITTLE_ENDIAN 26 | #endif 27 | 28 | #endif /* ENDIANNESS_H_ */ 29 | -------------------------------------------------------------------------------- /examples/ringserver.c: -------------------------------------------------------------------------------- 1 | /* example of a simple server that plays a wave file using aplay when 2 | someone connects. */ 3 | 4 | #include "../rocksockserver.h" 5 | #include 6 | #include 7 | 8 | int on_clientconnect (void* userdata, struct sockaddr_storage* clientaddr, int fd) { 9 | rocksockserver *s = userdata; 10 | rocksockserver_disconnect_client(s, fd); 11 | pid_t pid = fork(); 12 | if(!pid) execl("/bin/sh", "/bin/sh", "-c", "aplay /root/ring.wav", (char*) 0); 13 | else waitpid(pid, 0, 0); 14 | return 0; 15 | } 16 | 17 | int main() { 18 | int port = 9999; 19 | char* listenip = "0.0.0.0"; 20 | rocksockserver s; 21 | if(rocksockserver_init(&s, listenip, port, &s)) return -1; 22 | if(rocksockserver_loop(&s, NULL, 0, &on_clientconnect, 0, 0, 0)) return -2; 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /rocksock_ssl_internal.h: -------------------------------------------------------------------------------- 1 | #ifndef ROCKSOCK_SSL_PRIVATE_H 2 | #define ROCKSOCK_SSL_PRIVATE_H 3 | 4 | #include "rocksock.h" 5 | 6 | const char* rocksock_ssl_strerror(rocksock *sock, int error); 7 | int rocksock_ssl_send(rocksock* sock, char* buf, size_t sz); 8 | int rocksock_ssl_recv(rocksock* sock, char* buf, size_t sz); 9 | int rocksock_ssl_connect_fd(rocksock* sock); 10 | void rocksock_ssl_free_context(rocksock *sock); 11 | int rocksock_ssl_peek(rocksock* sock, int *result); 12 | int rocksock_ssl_pending(rocksock *sock); 13 | 14 | /* if you want cyassl, put both -DUSE_SSL and -DUSE_CYASSL 15 | in your CFLAGS. 16 | for openssl use -DUSE_SSL and -DUSE_OPENSSL. 17 | */ 18 | #ifdef USE_SSL 19 | 20 | #ifdef USE_CYASSL 21 | #pragma RcB2 DEP "rocksock_cyassl.c" 22 | #elif defined(USE_OPENSSL) 23 | #pragma RcB2 DEP "rocksock_openssl.c" 24 | #else 25 | #error "need to define one of USE_OPENSSL or USE_CYASSL with -DUSE_SSL" 26 | #endif 27 | 28 | #else 29 | #warning "compiling without SSL support" 30 | #pragma RcB2 DEP "rocksock_ssl.c" 31 | #endif 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /rocksockirc/rsirc.h: -------------------------------------------------------------------------------- 1 | #include "../rocksock.h" 2 | 3 | typedef struct rsirc { 4 | struct rocksock *s; 5 | } rsirc; 6 | 7 | int rsirc_init(struct rsirc *r, struct rocksock *s); 8 | int rsirc_handshake(struct rsirc *r, const char* host, const char* nick, const char* user); 9 | int rsirc_sendline(struct rsirc *r, const char *line); 10 | int rsirc_sendlinef(struct rsirc *r, const char* fmt, ...); 11 | int rsirc_privmsg(struct rsirc *r, const char *chan, const char *msg); 12 | int rsirc_privmsgf(struct rsirc *r, const char *dest, const char *fmt, ...); 13 | int rsirc_process(struct rsirc *r, char linebuf[512], size_t *rcvd); 14 | 15 | #if 0 16 | enum rsirc_event { 17 | RSI_EVENT_NONE = 0, 18 | RSI_EVENT_UNKNOWN, 19 | RSI_EVENT_SYS_MSG, 20 | RSI_EVENT_MOTD_START, 21 | RSI_EVENT_MOTD_LINE, 22 | RSI_EVENT_MOTD_FINISH, 23 | RSI_EVENT_JOIN, 24 | RSI_EVENT_CHAN_TOPIC, 25 | RSI_EVENT_CHAN_TOPIC_SETTER, 26 | RSI_EVENT_NAMES_LINE, 27 | RSI_EVENT_NAMES_END, 28 | RSI_EVENT_NOTICE, 29 | RSI_EVENT_PRIVMSG, 30 | }; 31 | #endif 32 | 33 | #pragma RcB2 DEP "rsirc.c" 34 | 35 | -------------------------------------------------------------------------------- /rocksockserver.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * author: rofl0r 4 | * 5 | * License: LGPL 2.1+ with static linking exception 6 | * 7 | * 8 | */ 9 | 10 | 11 | #ifndef _ROCKSOCKSERVER_H_ 12 | #define _ROCKSOCKSERVER_H_ 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | #if (! defined(USER_MAX_FD)) || (USER_MAX_FD > FD_SETSIZE) 19 | #undef USER_MAX_FD 20 | #define USER_MAX_FD FD_SETSIZE 21 | #endif 22 | 23 | typedef void (*perror_func)(const char*); 24 | typedef struct { 25 | fd_set master; 26 | int listensocket; 27 | int maxfd; 28 | int numfds; 29 | int signalfd; 30 | void* userdata; 31 | long sleeptime_us; 32 | perror_func perr; 33 | } rocksockserver; 34 | 35 | void rocksockserver_set_sleeptime(rocksockserver* srv, long microsecs); 36 | int rocksockserver_disconnect_client(rocksockserver* srv, int client); 37 | int rocksockserver_init(rocksockserver* srv, const char* listenip, unsigned short port, void* userdata); 38 | void rocksockserver_watch_fd(rocksockserver* srv, int newfd); 39 | void rocksockserver_set_signalfd(rocksockserver* srv, int signalfd); 40 | void rocksockserver_set_perrorfunc(rocksockserver* srv, perror_func perr); 41 | int rocksockserver_loop(rocksockserver* srv, 42 | char* buf, size_t bufsize, 43 | int (*on_clientconnect) (void* userdata, struct sockaddr_storage* clientaddr, int fd), 44 | int (*on_clientread) (void* userdata, int fd, size_t nread), 45 | int (*on_clientwantsdata) (void* userdata, int fd), 46 | int (*on_clientdisconnect) (void* userdata, int fd) 47 | ); 48 | 49 | #pragma RcB2 DEP "rocksockserver*.c" 50 | 51 | #endif 52 | 53 | -------------------------------------------------------------------------------- /rocksock_add_proxy.c: -------------------------------------------------------------------------------- 1 | #undef _POSIX_C_SOURCE 2 | #define _POSIX_C_SOURCE 200809L 3 | #undef _GNU_SOURCE 4 | #define _GNU_SOURCE 5 | 6 | #include 7 | 8 | #include "rocksock.h" 9 | #include "rocksock_internal.h" 10 | 11 | #ifndef ROCKSOCK_FILENAME 12 | #define ROCKSOCK_FILENAME __FILE__ 13 | #endif 14 | 15 | int rocksock_add_proxy(rocksock* sock, rs_proxyType proxytype, const char* host, unsigned short port, const char* username, const char* password) { 16 | rs_proxy* prx; 17 | if (!sock) 18 | return RS_E_NULL; 19 | if(!host) 20 | return rocksock_seterror(sock, RS_ET_OWN, RS_E_NULL, ROCKSOCK_FILENAME, __LINE__); 21 | if(proxytype == RS_PT_SOCKS4 && (username || password)) 22 | return rocksock_seterror(sock, RS_ET_OWN, RS_E_SOCKS4_NOAUTH, ROCKSOCK_FILENAME, __LINE__); 23 | if(proxytype == RS_PT_SOCKS5 && ((username && strlen(username) > 255) || (password && strlen(password) > 255))) 24 | return rocksock_seterror(sock, RS_ET_OWN, RS_E_SOCKS5_AUTH_EXCEEDSIZE, ROCKSOCK_FILENAME, __LINE__); 25 | if(!sock->proxies) 26 | return rocksock_seterror(sock, RS_ET_OWN, RS_E_NO_PROXYSTORAGE, ROCKSOCK_FILENAME, __LINE__); 27 | size_t l = strlen(host); 28 | if(l > 255) 29 | return rocksock_seterror(sock, RS_ET_OWN, RS_E_HOSTNAME_TOO_LONG, ROCKSOCK_FILENAME, __LINE__); 30 | sock->lastproxy++; 31 | prx = &sock->proxies[sock->lastproxy]; 32 | prx->hostinfo.port = port; 33 | prx->proxytype = proxytype; 34 | memcpy(prx->hostinfo.host, host, l+1); 35 | memcpy(prx->username, username?username:"", username?strlen(username)+1:1); 36 | memcpy(prx->password, password?password:"", password?strlen(password)+1:1); 37 | return rocksock_seterror(sock, RS_ET_OWN, 0, NULL, 0); 38 | } 39 | 40 | -------------------------------------------------------------------------------- /rocksock_readline.c: -------------------------------------------------------------------------------- 1 | /* 2 | * author: rofl0r (C) 2011-2013 3 | * License: LGPL 2.1+ with static linking exception 4 | */ 5 | 6 | #undef _POSIX_C_SOURCE 7 | #define _POSIX_C_SOURCE 200809L 8 | #undef _GNU_SOURCE 9 | #define _GNU_SOURCE 10 | 11 | #include 12 | #include "rocksock_internal.h" 13 | 14 | #ifndef ROCKSOCK_FILENAME 15 | #define ROCKSOCK_FILENAME __FILE__ 16 | #endif 17 | 18 | // tries to read exactly one line, until '\n', then overwrites the \n with \0 19 | // bytesread contains the number of bytes read till \n was encountered 20 | // (so 0 in case \n was the first char). 21 | // returns RS_E_OUT_OF_BUFFER if the line doesnt fit into the buffer. 22 | int rocksock_readline(rocksock* sock, char* buffer, size_t bufsize, size_t* bytesread) { 23 | // TODO: make more efficient by peeking into the buffer (Flag MSG_PEEK to recv), instead of reading byte by byte 24 | // would need a different approach for ssl though. 25 | if (!sock) return RS_E_NULL; 26 | if (!buffer || !bufsize || !bytesread) 27 | return rocksock_seterror(sock, RS_ET_OWN, RS_E_NULL, 28 | ROCKSOCK_FILENAME, __LINE__); 29 | char* ptr = buffer; 30 | size_t bytesread2 = 0; 31 | int ret; 32 | *bytesread = 0; 33 | while(*bytesread < bufsize) { 34 | ret = rocksock_recv(sock, ptr, 1, 1, &bytesread2); 35 | if(ret || !bytesread2) return ret; 36 | *bytesread += bytesread2; 37 | if(ptr > buffer + bufsize) 38 | break; 39 | if(*bytesread > bufsize) { 40 | *bytesread = bufsize; 41 | break; 42 | } 43 | if(*ptr == '\n') { 44 | *ptr = 0; 45 | *bytesread -= 1; 46 | return 0; 47 | } 48 | ptr++; 49 | } 50 | return rocksock_seterror(sock, RS_ET_OWN, RS_E_OUT_OF_BUFFER, 51 | ROCKSOCK_FILENAME, __LINE__); 52 | } 53 | -------------------------------------------------------------------------------- /rocksock_peek.c: -------------------------------------------------------------------------------- 1 | /* 2 | * author: rofl0r (C) 2011-2013 3 | * License: LGPL 2.1+ with static linking exception 4 | */ 5 | 6 | #undef _POSIX_C_SOURCE 7 | #define _POSIX_C_SOURCE 200809L 8 | #undef _GNU_SOURCE 9 | #define _GNU_SOURCE 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "rocksock.h" 17 | #include "rocksock_internal.h" 18 | #ifdef USE_SSL 19 | #include "rocksock_ssl_internal.h" 20 | #endif 21 | 22 | #ifndef ROCKSOCK_FILENAME 23 | #define ROCKSOCK_FILENAME __FILE__ 24 | #endif 25 | 26 | /* 27 | return value: error code or 0 for no error 28 | result will contain 0 if no data is available, 1 if data is available. 29 | if data is available, and a subsequent recv call returns 0 bytes read, the 30 | connection was terminated. */ 31 | int rocksock_peek(rocksock* sock, int *result) { 32 | ssize_t readv; 33 | if(!result) 34 | return rocksock_seterror(sock, RS_ET_OWN, RS_E_NULL, ROCKSOCK_FILENAME, __LINE__); 35 | if (sock->socket == -1) return rocksock_seterror(sock, RS_ET_OWN, RS_E_NO_SOCKET, ROCKSOCK_FILENAME, __LINE__); 36 | #ifdef USE_SSL 37 | if(sock->ssl && rocksock_ssl_pending(sock)) { 38 | *result = 1; 39 | goto no_err; 40 | } 41 | #endif 42 | fd_set readfds; 43 | 44 | struct timeval tv; 45 | tv.tv_sec = 0; 46 | tv.tv_usec = 1; 47 | FD_ZERO(&readfds); 48 | FD_SET(sock->socket, &readfds); 49 | 50 | readv = select(sock->socket + 1, &readfds, 0, 0, &tv); 51 | if(readv < 0) return rocksock_seterror(sock, RS_ET_SYS, errno, ROCKSOCK_FILENAME, __LINE__); 52 | *result = FD_ISSET(sock->socket, &readfds); 53 | #ifdef USE_SSL 54 | if(sock->ssl && *result) { 55 | return rocksock_ssl_peek(sock, result); 56 | } 57 | no_err: 58 | #endif 59 | return rocksock_seterror(sock, RS_ET_OWN, 0, NULL, 0); 60 | } 61 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Makefile for proxychains (requires GNU make), stolen from musl 3 | # 4 | # Use config.mak to override any of the following variables. 5 | # Do not make changes here. 6 | # 7 | prefix = /usr/local 8 | exec_prefix = $(prefix) 9 | bindir = $(exec_prefix)/bin 10 | includedir = $(prefix)/include 11 | libdir = $(prefix)/lib 12 | 13 | SRCS = $(sort $(wildcard *.c)) 14 | OBJS = $(SRCS:.c=.o) 15 | LOBJS = $(OBJS:.o=.lo) 16 | SONAME = librocksock.so 17 | ANAME = librocksock.a 18 | 19 | #EX_SRCS = $(sort $(wildcard examples/*.c)) 20 | EX_SRCS = examples/http_test.c examples/rocksock_test3.c \ 21 | examples/ssh-socks-restart.c examples/proxychk.c 22 | EX_PROGS = $(EX_SRCS:.c=.out) 23 | 24 | CFLAGS += -Wall -std=c99 -D_GNU_SOURCE -pipe 25 | INC = 26 | PIC = -fPIC -shared 27 | AR = $(CROSS_COMPILE)ar 28 | RANLIB = $(CROSS_COMPILE)ranlib 29 | ALL_LIBS = $(ANAME) 30 | ALL_INCLUDES = rocksock.h 31 | 32 | -include config.mak 33 | 34 | examples: $(ALL_LIBS) $(EX_PROGS) 35 | 36 | 37 | all: $(ALL_LIBS) 38 | 39 | install: $(ALL_LIBS:lib%=$(DESTDIR)$(libdir)/lib%) $(ALL_INCLUDES:%=$(DESTDIR)$(includedir)/%) 40 | 41 | $(DESTDIR)$(libdir)/%: $(ALL_LIBS) 42 | install -D -m 644 $< $@ 43 | 44 | $(DESTDIR)$(lincludedir)/%: $(ALL_INCLUDES) 45 | install -D -m 644 $< $@ 46 | 47 | $(SONAME): $(LOBJS) 48 | $(CC) $(PIC) -Wl,-soname=$(SONAME) -o $(SONAME) $(LOBJS) $(LDFLAGS) 49 | 50 | $(ANAME): $(OBJS) 51 | rm -f $@ 52 | $(AR) rc $@ $(OBJS) 53 | $(RANLIB) $@ 54 | 55 | clean: 56 | rm -f $(OBJS) 57 | rm -f $(LOBJS) 58 | rm -f $(EX_PROGS) 59 | 60 | %.o: %.c config.mak 61 | $(CC) $(CPPFLAGS) $(CFLAGS) $(INC) -c -o $@ $< 62 | 63 | %.lo: %.c config.mak 64 | $(CC) $(CPPFLAGS) $(CFLAGS) $(PIC) $(INC) -c -o $@ $< 65 | 66 | examples/micserver.out: LDFLAGS+=-lasound 67 | 68 | %.out: %.c $(ANAME) 69 | $(CC) $(CPPFLAGS) $(CFLAGS) $(INC) -o $@ $< -L. -lrocksock $(LDFLAGS) 70 | 71 | 72 | .PHONY: all clean install 73 | -------------------------------------------------------------------------------- /rocksockirc/rsirc.c: -------------------------------------------------------------------------------- 1 | #include "../rocksock.h" 2 | #include "rsirc.h" 3 | #include 4 | #ifdef USE_LIBULZ_SYS 5 | #include 6 | #elif defined(USE_LIBULZ) 7 | #include 8 | #endif 9 | #include 10 | #include 11 | 12 | #define chk(x) if((ret = x)) return ret 13 | #define sendl(x) rsirc_sendline(r, x) 14 | 15 | int rsirc_init(struct rsirc *r, struct rocksock *s) { 16 | r->s = s; 17 | return 0; 18 | } 19 | 20 | int rsirc_sendline(struct rsirc *r, const char *line) { 21 | char buf[512]; 22 | size_t written; 23 | // FIXME loop over this when strlen(line) > 510 24 | dprintf(2, "wrote %zu bytes\n", snprintf(buf, sizeof(buf), "%s\r\n", line)); 25 | return rocksock_send(r->s, buf, 0, 0, &written); 26 | } 27 | 28 | int rsirc_sendlinef(struct rsirc *r, const char* fmt, ...) { 29 | va_list ap; 30 | va_start(ap, fmt); 31 | char buf[512]; 32 | vsnprintf(buf, sizeof buf, fmt, ap); 33 | va_end(ap); 34 | return sendl(buf); 35 | } 36 | 37 | int rsirc_privmsg(struct rsirc *r, const char *chan, const char *msg) { 38 | char buf[512]; 39 | snprintf(buf, sizeof buf, "PRIVMSG %s :%s", chan, msg); 40 | return sendl(buf); 41 | } 42 | 43 | int rsirc_privmsgf(struct rsirc *r, const char *dest, const char *fmt, ...) { 44 | va_list ap; 45 | va_start(ap, fmt); 46 | char buf[512]; 47 | vsnprintf(buf, sizeof buf, fmt, ap); 48 | va_end(ap); 49 | return rsirc_privmsg(r, dest, buf); 50 | } 51 | 52 | int rsirc_handshake(struct rsirc *r, const char* host, const char* nick, const char* user) { 53 | char cmdbuf[512]; 54 | int ret; 55 | snprintf(cmdbuf, sizeof(cmdbuf), "NICK %s", nick); 56 | chk(sendl(cmdbuf)); 57 | snprintf(cmdbuf, sizeof(cmdbuf), "USER %s %s %s :%s", user, user, host, nick); 58 | chk(sendl(cmdbuf)); 59 | return 0; 60 | } 61 | 62 | int rsirc_process(struct rsirc *r, char linebuf[512], size_t *rcvd) { 63 | int ret, has_data = 0; 64 | *rcvd = 0; 65 | chk(rocksock_peek(r->s, &has_data)); 66 | if(has_data) { 67 | chk(rocksock_readline(r->s, linebuf, 512, rcvd)); 68 | assert(*rcvd < 512); 69 | if(*rcvd != 0) { 70 | assert(*rcvd >= 1); 71 | assert(linebuf[(*rcvd) - 1] == '\r'); 72 | linebuf[(*rcvd) - 1] = 0; 73 | } 74 | } 75 | return 0; 76 | } 77 | -------------------------------------------------------------------------------- /examples/http_test.c: -------------------------------------------------------------------------------- 1 | // gcc -Wall -g rocksock.c rocksock_test2.c -o rocksock_test2 2 | /* 3 | * author: rofl0r 4 | * 5 | * License: LGPL 2.1+ with static linking exception 6 | */ 7 | #include 8 | #include 9 | #include "../rocksock.h" 10 | 11 | #define chk(X, ACTION) if(X) { rocksock_error_dprintf(2, psock); ACTION; } 12 | #define checkerr chk(ret, exit(2)) 13 | 14 | static int usage(const char *a0) { 15 | dprintf(2, 16 | "usage: %s host port [proxy1] [proxy2] ... [proxy16]\n" 17 | "makes a HTTP connection to host on port. if port ends with s,\n" 18 | "SSL will be used. supports up to 16 chained proxies.\n" 19 | "proxies will be chained in the order as they appear.\n\n" 20 | "supported proxy syntax:\n" 21 | "http://proxy.com:port - HTTP proxy like squid or tinyproxy\n" 22 | "socks4://proxy.com:port - SOCKS4 proxy like tor\n" 23 | "socks5://proxy.com:port - SOCKS5 proxy like rocksocks5\n" 24 | "socks5://user:pass@proxy.com:port - SOCKS5 proxy with auth\n\n" 25 | "example: %s googe.com 80 http://localhost:8888\n" 26 | "example: %s googe.com 443s socks4://localhost:9050\n", a0, a0, a0); 27 | return 1; 28 | } 29 | 30 | int main(int argc, char** argv) { 31 | rocksock sock; 32 | rocksock* psock = &sock; 33 | int ret, i; 34 | char inbuf[1024]; 35 | size_t bytesread; 36 | size_t chunksize = 512; 37 | 38 | if(argc < 3) return usage(argv[0]); 39 | 40 | rocksock_init_ssl(); 41 | 42 | rs_proxy proxies[16]; 43 | rocksock_init(psock, proxies); 44 | rocksock_set_timeout(psock, 10000); 45 | for (i = 3; i < argc; i++) chk(rocksock_add_proxy_fromstring(psock, argv[i]), return usage(argv[0])); 46 | unsigned port = atoi(argv[2]); 47 | int useSSL = 0; 48 | char *p = argv[2]; while(*p) p++; 49 | if(p[-1] == 's') useSSL = 1; 50 | 51 | ret = rocksock_connect(psock, argv[1], port, useSSL); 52 | 53 | checkerr; 54 | ret = rocksock_send(psock, "GET / HTTP/1.0\r\n\r\n", 0, 0, &bytesread); 55 | 56 | checkerr; 57 | do { 58 | puts("loop"); 59 | ret = rocksock_recv(psock, inbuf, sizeof(inbuf)-1, chunksize, &bytesread); 60 | checkerr; 61 | if(bytesread) { 62 | inbuf[bytesread] = '\0'; 63 | puts(inbuf); 64 | } 65 | printf("bytesread %zu\n", bytesread); 66 | } while (bytesread == chunksize); 67 | do { 68 | 69 | ret = rocksock_recv(psock, inbuf, sizeof(inbuf)-1, chunksize, &bytesread); 70 | checkerr; 71 | if(bytesread) { 72 | inbuf[bytesread] = '\0'; 73 | puts(inbuf); 74 | } 75 | printf("bytesread %zu\n", bytesread); 76 | } while (bytesread); 77 | rocksock_disconnect(psock); 78 | rocksock_clear(psock); 79 | rocksock_free_ssl(); 80 | return 0; 81 | } 82 | -------------------------------------------------------------------------------- /examples/micclient.c: -------------------------------------------------------------------------------- 1 | /* 2 | * author: rofl0r 3 | * 4 | * License: LGPL 2.1+ with static linking exception 5 | 6 | * streams microphone input to a server 7 | * use arecord -L to see available alsa device names 8 | 9 | */ 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "micbuffer.h" 16 | 17 | #include "../rocksock.h" 18 | 19 | //RcB: CFLAGS "-std=c99 -D_GNU_SOURCE -Wall" 20 | //RcB: LINK "-lasound" 21 | 22 | #define chks(X, ACTION) if(X) { rocksock_error_dprintf(2, psock); ACTION; } 23 | #define checkerr() chks(ret, exit(2)) 24 | 25 | static void chk(const int err, const char* msg) { 26 | if(err < 0) { 27 | fprintf(stderr, msg, snd_strerror(err)); 28 | exit(1); 29 | } 30 | } 31 | 32 | static snd_pcm_t* init_record_device(const char* devname) { 33 | snd_pcm_t *capture_handle; 34 | snd_pcm_hw_params_t *hw_params; 35 | chk(snd_pcm_open(&capture_handle, devname, SND_PCM_STREAM_CAPTURE, 0), "cannot open audio device (%s)\n"); 36 | chk(snd_pcm_hw_params_malloc(&hw_params), "cannot allocate hardware parameter structure (%s)\n"); 37 | chk(snd_pcm_hw_params_any(capture_handle, hw_params), "cannot initialize hardware parameter structure (%s)\n"); 38 | chk(snd_pcm_hw_params_set_access(capture_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED),"cannot set access type (%s)\n"); 39 | chk(snd_pcm_hw_params_set_format(capture_handle, hw_params, FORMAT),"cannot set sample format (%s)\n"); 40 | unsigned rate = BITRATE; 41 | chk(snd_pcm_hw_params_set_rate_near(capture_handle, hw_params, &rate,0),"cannot set sample rate (%s)\n"); 42 | chk(snd_pcm_hw_params_set_channels(capture_handle, hw_params, NUMCHANNELS),"cannot set channel count (%s)\n"); 43 | chk(snd_pcm_hw_params(capture_handle, hw_params),"cannot set parameters (%s)\n"); 44 | snd_pcm_hw_params_free(hw_params); 45 | chk(snd_pcm_prepare(capture_handle),"cannot prepare audio interface for use (%s)\n"); 46 | return capture_handle; 47 | } 48 | 49 | static int interrupted; 50 | static void sigint(int dummy) { 51 | (void) dummy; 52 | interrupted = 1; 53 | } 54 | 55 | int main(int argc, char** argv) { 56 | rocksock sock; 57 | rocksock* psock = &sock; 58 | int ret; 59 | unsigned char inbuf[MIC_BUFFER_SIZE]; 60 | size_t bytesread; 61 | 62 | if(argc < 3) { 63 | puts("need ip or dns name of server as argv1 and alsa devicename as argv2"); 64 | return 1; 65 | } 66 | 67 | rocksock_init(psock, NULL); 68 | rocksock_set_timeout(psock, 10000); 69 | 70 | ret = rocksock_connect(psock, argv[1], 9999, 0); 71 | checkerr(); 72 | 73 | snd_pcm_t *capture_handle = init_record_device(argv[2]); 74 | signal(SIGINT, sigint); 75 | while(!interrupted) { 76 | chk(snd_pcm_readi(capture_handle, inbuf, sizeof inbuf), "read from audio interface failed (%s)\n"); 77 | ret = rocksock_send(psock, (void*)inbuf, sizeof inbuf, sizeof inbuf, &bytesread); 78 | checkerr(); 79 | } 80 | snd_pcm_close(capture_handle); 81 | rocksock_disconnect(psock); 82 | rocksock_clear(psock); 83 | return 0; 84 | } 85 | -------------------------------------------------------------------------------- /rocksock_add_proxy_fromstring.c: -------------------------------------------------------------------------------- 1 | #undef _POSIX_C_SOURCE 2 | #define _POSIX_C_SOURCE 200809L 3 | #undef _GNU_SOURCE 4 | #define _GNU_SOURCE 5 | 6 | #include 7 | #include /* for atoi() */ 8 | 9 | #include "rocksock.h" 10 | #include "rocksock_internal.h" 11 | 12 | #ifndef ROCKSOCK_FILENAME 13 | #define ROCKSOCK_FILENAME __FILE__ 14 | #endif 15 | 16 | /* valid inputs: 17 | socks5://user:password@proxy.domain.com:port 18 | socks5://proxy.domain.com:port 19 | socks4://proxy.domain.com:port 20 | http://user:password@proxy.domain.com:port 21 | http://proxy.domain.com:port 22 | 23 | supplying port number is obligatory. 24 | user:pass@ part is optional for http and socks5. 25 | however, user:pass authentication is currently not implemented for http proxies. 26 | */ 27 | #define MKERR(S, X) rocksock_seterror(S, RS_ET_OWN, X, ROCKSOCK_FILENAME, __LINE__) 28 | int rocksock_add_proxy_fromstring(rocksock* sock, const char *proxystring) { 29 | if (!sock) 30 | return RS_E_NULL; 31 | if(!sock->proxies) return MKERR(sock, RS_E_NO_PROXYSTORAGE); 32 | 33 | const char* p; 34 | rs_proxyType proxytype; 35 | rs_proxy* prx = &sock->proxies[sock->lastproxy+1]; 36 | char *user_buf = prx->username; 37 | char *pass_buf = prx->password; 38 | char *host_buf = prx->hostinfo.host; 39 | size_t next_token = 6, ul = 0, pl = 0, hl; 40 | if(!proxystring[0] || !proxystring[1] || !proxystring[2] || !proxystring[3] || !proxystring[4] || !proxystring[5]) goto inv_string; 41 | if(*proxystring == 's') { 42 | switch(proxystring[5]) { 43 | case '5': proxytype = RS_PT_SOCKS5; break; 44 | case '4': proxytype = RS_PT_SOCKS4; break; 45 | default: goto inv_string; 46 | } 47 | } else if(*proxystring == 'h') { 48 | proxytype = RS_PT_HTTP; 49 | next_token = 4; 50 | } else goto inv_string; 51 | if( 52 | proxystring[next_token++] != ':' || 53 | proxystring[next_token++] != '/' || 54 | proxystring[next_token++] != '/') goto inv_string; 55 | const char *at = strrchr(proxystring+next_token, '@'); 56 | if(at) { 57 | if(proxytype == RS_PT_SOCKS4) 58 | return MKERR(sock, RS_E_SOCKS4_NOAUTH); 59 | p = strchr(proxystring+next_token, ':'); 60 | if(!p || p >= at) goto inv_string; 61 | const char *u = proxystring+next_token; 62 | ul = p-u; 63 | p++; 64 | pl = at-p; 65 | if(proxytype == RS_PT_SOCKS5 && (ul > 255 || pl > 255)) 66 | return MKERR(sock, RS_E_SOCKS5_AUTH_EXCEEDSIZE); 67 | memcpy(user_buf, u, ul); 68 | user_buf[ul]=0; 69 | memcpy(pass_buf, p, pl); 70 | pass_buf[pl]=0; 71 | next_token += 2+ul+pl; 72 | } else { 73 | user_buf[0]=0; 74 | pass_buf[0]=0; 75 | } 76 | const char* h = proxystring+next_token; 77 | p = strchr(h, ':'); 78 | if(!p) goto inv_string; 79 | hl = p-h; 80 | if(hl > 255) 81 | return MKERR(sock, RS_E_HOSTNAME_TOO_LONG); 82 | memcpy(host_buf, h, hl); 83 | host_buf[hl]=0; 84 | sock->lastproxy++; 85 | prx->hostinfo.port = atoi(p+1); 86 | prx->proxytype = proxytype; 87 | return rocksock_seterror(sock, RS_ET_OWN, 0, NULL, 0); 88 | inv_string: 89 | return MKERR(sock, RS_E_INVALID_PROXY_URL); 90 | } 91 | 92 | -------------------------------------------------------------------------------- /examples/rocksock_test3.c: -------------------------------------------------------------------------------- 1 | // gcc -Wall -g rocksock.c rocksock_test2.c -o rocksock_test2 2 | 3 | /* 4 | * 5 | * author: rofl0r 6 | * 7 | * License: LGPL 2.1+ with static linking exception 8 | * 9 | * 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | #include "../rocksock.h" 16 | 17 | #define chk(X, ACTION) if(X) { rocksock_error_dprintf(2, psock); ACTION; } 18 | #define checkerr chk(ret, exit(2)) 19 | 20 | int main(int argc, char** argv) { 21 | rocksock sock; 22 | rocksock* psock = &sock; 23 | int ret; 24 | char inbuf[1024]; 25 | size_t bytesread; 26 | size_t chunksize = 512; 27 | 28 | if(argc < 2) { 29 | puts("need ip or dns name of a ftpserver as argv1"); 30 | exit(1); 31 | } 32 | #ifdef USE_SSL 33 | rocksock_init_ssl(); 34 | #endif 35 | rs_proxy proxies[4]; 36 | rocksock_init(psock, proxies); 37 | rocksock_set_timeout(psock, 10000); 38 | //ret = rocksock_connect(psock, "b12.wimbli.com", 80, 0); 39 | rocksock_add_proxy(psock, RS_PT_SOCKS4, "127.0.0.1", 9050, NULL, NULL); 40 | //rocksock_add_proxy(psock, RS_PT_SOCKS5, "127.0.0.1", 31337, NULL, NULL); 41 | //rocksock_add_proxy(psock, RS_PT_SOCKS5, "98.216.80.12", 5639, NULL, NULL); 42 | 43 | 44 | ret = rocksock_connect(psock, argv[1], 45 | #ifndef USE_SSL 46 | 21, 0 47 | #else 48 | 443, 1 49 | #endif 50 | ); 51 | checkerr; 52 | do { 53 | ret = rocksock_readline(psock, inbuf, sizeof(inbuf)-1, &bytesread); 54 | checkerr; 55 | if(bytesread) puts(inbuf); 56 | } while (bytesread && memcmp(inbuf, "220 ", 4)); 57 | 58 | ret = rocksock_send(psock, inbuf, snprintf(inbuf, sizeof(inbuf), "USER ftp\r\n"), 0, &bytesread); 59 | checkerr; 60 | puts(inbuf); 61 | 62 | do { 63 | ret = rocksock_readline(psock, inbuf, sizeof(inbuf)-1, &bytesread); 64 | checkerr; 65 | if(bytesread) puts(inbuf); 66 | } while (bytesread && memcmp(inbuf, "331 ", 4)); 67 | 68 | ret = rocksock_send(psock, inbuf, snprintf(inbuf, sizeof(inbuf), "PASS none\r\n"), 0, &bytesread); 69 | checkerr; 70 | puts(inbuf); 71 | 72 | do { 73 | ret = rocksock_readline(psock, inbuf, sizeof(inbuf)-1, &bytesread); 74 | checkerr; 75 | if(bytesread) puts(inbuf); 76 | } while (bytesread && memcmp(inbuf, "230 ", 4)); 77 | 78 | ret = rocksock_send(psock, inbuf, snprintf(inbuf, sizeof(inbuf), "PASV\r\n"), 0, &bytesread); 79 | checkerr; 80 | puts(inbuf); 81 | 82 | do { 83 | ret = rocksock_readline(psock, inbuf, sizeof(inbuf)-1, &bytesread); 84 | checkerr; 85 | if(bytesread) puts(inbuf); 86 | } while (bytesread && memcmp(inbuf, "230 ", 4)); 87 | 88 | ret = rocksock_send(psock, inbuf, snprintf(inbuf, sizeof(inbuf), "LIST\r\n"), 0, &bytesread); 89 | checkerr; 90 | puts(inbuf); 91 | 92 | do { 93 | ret = rocksock_readline(psock, inbuf, sizeof(inbuf)-1, &bytesread); 94 | checkerr; 95 | if(bytesread) puts(inbuf); 96 | } while (bytesread && memcmp(inbuf, "230 ", 4)); 97 | 98 | ret = rocksock_readline(psock, inbuf, sizeof(inbuf)-1, &bytesread); 99 | checkerr; 100 | if(bytesread) puts(inbuf); 101 | 102 | rocksock_disconnect(psock); 103 | rocksock_clear(psock); 104 | #ifdef USE_SSL 105 | rocksock_free_ssl(); 106 | #endif 107 | return 0; 108 | } 109 | -------------------------------------------------------------------------------- /rocksock_strerror.c: -------------------------------------------------------------------------------- 1 | #include "rocksock.h" 2 | #include "rocksock_internal.h" 3 | #include 4 | #ifndef NO_DNS_SUPPORT 5 | #include 6 | #endif 7 | #ifdef USE_SSL 8 | #include "rocksock_ssl_internal.h" 9 | #endif 10 | 11 | #ifdef ROCKSOCK_FILENAME 12 | static const char rs_errorMap[][3] = { 13 | "0" , "1" , "2" , "3" , "4" , "5" , "6" , "7", 14 | "8" , "9" , "10", "11", "12", "13", "14", "15", 15 | "16", "17", "18", "19", "20", "21", "22", "23", 16 | "24", "25", "26", "27" 17 | }; 18 | 19 | #else 20 | 21 | static const char* rs_errorMap[] = { 22 | // RS_E_NO_ERROR, 23 | "no error", 24 | //RS_E_NULL, 25 | "NULL pointer passed", 26 | //RS_E_EXCEED_PROXY_LIMIT, 27 | "exceeding maximum number of proxies", 28 | //RS_E_NO_SSL, 29 | "can not establish SSL connection, since library was not compiled with USE_SSL define", 30 | // RS_E_NO_SOCKET 31 | "socket is not set up, maybe you should call connect first", 32 | // RS_E_HIT_TIMEOUT 33 | "timeout reached on operation", 34 | //RS_E_OUT_OF_BUFFER 35 | "supplied buffer is too small", 36 | // RS_E_SSL_GENERIC 37 | "generic SSL error, see STDERR", 38 | // RS_E_SOCKS4_NOAUTH 39 | "SOCKS4 authentication not implemented", 40 | // RS_E_SOCKS5_AUTH_EXCEEDSIZE 41 | "maximum length for SOCKS5 servername/password/username is 255", 42 | // RS_E_SOCKS4_NO_IP6 43 | "SOCKS4 is not compatible with IPv6", 44 | // RS_E_PROXY_UNEXPECTED_RESPONSE 45 | "the proxy sent an unexpected response", 46 | // RS_E_TARGETPROXY_CONNECT_FAILED 47 | "could not connect to target proxy", 48 | // RS_E_PROXY_AUTH_FAILED 49 | "proxy authentication failed or authd not enabled", 50 | //RS_E_HIT_READTIMEOUT = 14, 51 | "timeout reached on read operation", 52 | //RS_E_HIT_WRITETIMEOUT = 15, 53 | "timeout reached on write operation", 54 | //RS_E_HIT_CONNECTTIMEOUT = 16, 55 | "timeout reached on connect operation", 56 | //RS_E_PROXY_GENERAL_FAILURE = 17, 57 | "proxy general failure", 58 | //RS_E_TARGETPROXY_NET_UNREACHABLE = 18, 59 | "proxy-target: net unreachable", 60 | //RS_E_TARGETPROXY_HOST_UNREACHABLE = 19, 61 | "proxy-target: host unreachable", 62 | //RS_E_TARGETPROXY_CONN_REFUSED = 20, 63 | "proxy-target: connection refused", 64 | //RS_E_TARGETPROXY_TTL_EXPIRED = 21, 65 | "proxy-target: TTL expired", 66 | //RS_E_PROXY_COMMAND_NOT_SUPPORTED = 22, 67 | "proxy: command not supported", 68 | //RS_E_PROXY_ADDRESSTYPE_NOT_SUPPORTED = 23, 69 | "proxy: addresstype not supported", 70 | //RS_E_REMOTE_DISCONNECTED = 24, 71 | "remote socket closed connection", 72 | //RS_E_NO_PROXYSTORAGE = 25, 73 | "no proxy storage assigned", 74 | //RS_E_HOSTNAME_TOO_LONG = 26, 75 | "hostname exceeds 255 chars", 76 | //RS_E_INVALID_PROXY_URL = 27, 77 | "invalid proxy URL string" 78 | }; 79 | 80 | #endif 81 | 82 | const char* rocksock_strerror(rocksock *sock) { 83 | int error = sock->lasterror.error; 84 | switch(sock->lasterror.errortype) { 85 | #ifndef NO_DNS_SUPPORT 86 | case RS_ET_GAI: 87 | return gai_strerror(error); 88 | #endif 89 | case RS_ET_OWN: 90 | if (error < RS_E_MAX_ERROR) 91 | return rs_errorMap[error]; 92 | return 0; 93 | case RS_ET_SYS: 94 | return strerror(error); 95 | #ifdef USE_SSL 96 | case RS_ET_SSL: { 97 | const char *tmp = rocksock_ssl_strerror(sock, error); 98 | if(!tmp) return rs_errorMap[RS_E_SSL_GENERIC]; 99 | return tmp; 100 | } 101 | #endif 102 | default: 103 | return 0; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /examples/polite_echoserver.c: -------------------------------------------------------------------------------- 1 | /* the polite echo server. requires you to send a HELO, afterwards 2 | mimics a traditional echo server */ 3 | 4 | #include "../rocksockserver.h" 5 | #include "../../lib/include/sblist.h" 6 | #include 7 | 8 | #pragma RcB2 CFLAGS "-std=c99" 9 | 10 | enum cstate { 11 | cs_null = 0, 12 | cs_error, 13 | cs_said_hello, 14 | cs_idle, 15 | cs_msg, 16 | }; 17 | 18 | typedef struct client { 19 | int fd; 20 | enum cstate state; 21 | char msg[128]; 22 | } client; 23 | 24 | typedef struct server_state { 25 | rocksockserver srv; 26 | sblist *clients; 27 | } server; 28 | 29 | struct client *client_from_fd(sblist *clients, int fd) { 30 | struct client* c; 31 | sblist_iter(clients, c) { 32 | if(c->fd == fd) return c; 33 | } 34 | return 0; 35 | } 36 | 37 | static void disconnect_client(server* s, int fd) { 38 | struct client *c; 39 | sblist_iter_counter(s->clients, i, c) { 40 | if(c->fd == fd) { 41 | sblist_delete(s->clients, i); 42 | break; 43 | } 44 | } 45 | rocksockserver_disconnect_client(&s->srv, fd); 46 | } 47 | 48 | static int on_cdisconnect (void* userdata, int fd) { 49 | server* s = userdata; 50 | disconnect_client(s, fd); 51 | return 0; 52 | } 53 | 54 | static int on_cconnect (void* userdata, struct sockaddr_storage* clientaddr, int fd) { 55 | server* s = userdata; 56 | struct client c = {.fd = fd }; 57 | if(!sblist_add(s->clients, &c)) { 58 | disconnect_client(s, fd); 59 | return -1; 60 | } 61 | return 0; 62 | } 63 | 64 | static void read_command(server *s, client *c, int fd) { 65 | ssize_t nbytes; 66 | if(c->state == cs_null) { 67 | if(5 != (nbytes = recv(fd, c->msg, 5, 0)) || 68 | memcmp(c->msg, "HELO\n", 5)) { 69 | c->state = cs_error; 70 | } else c->state = cs_said_hello; 71 | } else if (c->state == cs_idle) { 72 | nbytes = recv(fd, c->msg, sizeof(c->msg)-1, 0); 73 | if (nbytes == 0) on_cdisconnect(s, fd); 74 | else if(nbytes < 1) c->state = cs_error; 75 | else { 76 | c->msg[nbytes] = 0; 77 | c->state = cs_msg; 78 | } 79 | } 80 | } 81 | 82 | static int on_cread (void* userdata, int fd, size_t dummy) { 83 | server* s = userdata; 84 | struct client *c; 85 | if(!(c = client_from_fd(s->clients, fd))) return -1; 86 | read_command(s, c, fd); 87 | return 0; 88 | } 89 | #define SL(X) X, sizeof(X)-1 90 | static int on_cwantsdata (void* userdata, int fd) { 91 | server* s = userdata; 92 | struct client *c; 93 | if(!(c = client_from_fd(s->clients, fd))) return -1; 94 | switch(c->state) { 95 | case cs_said_hello: 96 | send(fd, SL("HELO. you may now say something.\n"), MSG_NOSIGNAL); 97 | c->state = cs_idle; 98 | case cs_idle: 99 | case cs_null: 100 | break; 101 | case cs_error: 102 | send(fd, SL("error: need to send HELO first\n"), MSG_NOSIGNAL); 103 | disconnect_client(s, fd); 104 | break; 105 | case cs_msg: 106 | send(fd, c->msg, strlen(c->msg), MSG_NOSIGNAL); 107 | c->state = cs_idle; 108 | break; 109 | } 110 | return 0; 111 | } 112 | 113 | int main() { 114 | server sv, *s = &sv; 115 | s->clients = sblist_new(sizeof(struct client), 32); 116 | const int port = 9999; 117 | const char* listenip = "0.0.0.0"; 118 | if(rocksockserver_init(&s->srv, listenip, port, (void*) s)) return -1; 119 | if(rocksockserver_loop(&s->srv, NULL, 0, 120 | &on_cconnect, &on_cread, 121 | &on_cwantsdata, &on_cdisconnect)) return -2; 122 | return 0; 123 | } 124 | -------------------------------------------------------------------------------- /rocksock_openssl.c: -------------------------------------------------------------------------------- 1 | /* 2 | * author: rofl0r (C) 2011 - 2013 3 | * License: LGPL 2.1+ with static linking exception 4 | */ 5 | 6 | #ifdef USE_OPENSSL 7 | 8 | #include "rocksock_ssl_internal.h" 9 | #include "rocksock_internal.h" 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | 18 | #ifndef ROCKSOCK_FILENAME 19 | #define ROCKSOCK_FILENAME __FILE__ 20 | #endif 21 | 22 | #pragma RcB2 LINK "-lssl" "-lcrypto" "-lz" 23 | 24 | void rocksock_init_ssl(void) { 25 | SSL_library_init(); 26 | SSL_load_error_strings(); 27 | SSLeay_add_ssl_algorithms(); 28 | } 29 | 30 | void rocksock_free_ssl(void) { 31 | // TODO: there are still 3 memblocks allocated from SSL_library_init (88 bytes) 32 | ERR_remove_state(0); 33 | ERR_free_strings(); 34 | EVP_cleanup(); 35 | CRYPTO_cleanup_all_ex_data(); 36 | } 37 | 38 | const char* rocksock_ssl_strerror(rocksock *sock, int error) { 39 | return ERR_reason_error_string(error); 40 | } 41 | 42 | #include 43 | int rocksock_ssl_send(rocksock* sock, char* buf, size_t sz) { 44 | int ret = SSL_write(sock->ssl, buf, sz); 45 | if (ret < 0 && SSL_get_error(sock->ssl, ret) == SSL_ERROR_WANT_WRITE) errno = EWOULDBLOCK; 46 | return ret; 47 | } 48 | 49 | int rocksock_ssl_recv(rocksock* sock, char* buf, size_t sz) { 50 | int ret = SSL_read(sock->ssl, buf, sz); 51 | if (ret < 0 && SSL_get_error(sock->ssl, ret) == SSL_ERROR_WANT_READ) errno = EWOULDBLOCK; 52 | return ret; 53 | } 54 | 55 | int rocksock_ssl_connect_fd(rocksock* sock) { 56 | sock->sslctx = SSL_CTX_new(SSLv23_client_method()); 57 | if (!sock->sslctx) { 58 | ERR_print_errors_fp(stderr); 59 | return rocksock_seterror(sock, RS_ET_OWN, RS_E_SSL_GENERIC, ROCKSOCK_FILENAME, __LINE__); 60 | } 61 | sock->ssl = SSL_new(sock->sslctx); 62 | if (!sock->ssl) { 63 | ERR_print_errors_fp(stderr); 64 | return rocksock_seterror(sock, RS_ET_OWN, RS_E_SSL_GENERIC, ROCKSOCK_FILENAME, __LINE__); 65 | } 66 | SSL_set_fd(sock->ssl, sock->socket); 67 | int ret = SSL_connect(sock->ssl); 68 | if(ret != 1) { 69 | if((ret = SSL_get_error(sock->ssl, ret)) == SSL_ERROR_WANT_READ) 70 | return rocksock_seterror(sock, RS_ET_OWN, RS_E_HIT_CONNECTTIMEOUT, ROCKSOCK_FILENAME, __LINE__); 71 | //ERR_print_errors_fp(stderr); 72 | //printf("%dxxx\n", SSL_get_error(sock->ssl, ret)); 73 | return rocksock_seterror(sock, RS_ET_SSL, ret, ROCKSOCK_FILENAME, __LINE__); 74 | } 75 | return 0; 76 | } 77 | 78 | void rocksock_ssl_free_context(rocksock *sock) { 79 | if(sock->ssl) { 80 | SSL_shutdown(sock->ssl); 81 | SSL_free(sock->ssl); 82 | SSL_CTX_free(sock->sslctx); 83 | sock->ssl = 0; 84 | } 85 | } 86 | 87 | int rocksock_ssl_pending(rocksock *sock) { 88 | return SSL_pending(sock->ssl); 89 | } 90 | 91 | int rocksock_ssl_peek(rocksock* sock, int *result) { 92 | char buf[4]; 93 | int ret; 94 | ret = SSL_peek(sock->ssl, buf, 1); 95 | if(ret >= 0) *result = 1; 96 | else { 97 | ret = SSL_get_error(sock->ssl, ret); 98 | if(ret == SSL_ERROR_WANT_READ) 99 | return rocksock_seterror(sock, RS_ET_OWN, RS_E_HIT_READTIMEOUT, ROCKSOCK_FILENAME, __LINE__); 100 | return rocksock_seterror(sock, RS_ET_SSL, ret, ROCKSOCK_FILENAME, __LINE__); 101 | } 102 | return rocksock_seterror(sock, RS_ET_OWN, 0, NULL, 0); 103 | } 104 | 105 | #endif 106 | 107 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | rocksock socket library (C) rofl0r 2 | ================================== 3 | 4 | rocksock is a powerful (mostly) blocking networking library 5 | written in C. 6 | it was designed for small size, robustness, simplicity, 7 | static linking and fine-grained error reporting and 8 | configurability. 9 | programming in a blocking way is much simpler, but can lead to 10 | near infinite blocking. rocksock addresses this by providing 11 | timeouts so the app doesn't get into a completely blocked 12 | state and can react properly on any exceptional condition. 13 | making the app fit for SSL only requires enabling one flag, and 14 | SOCKS/HTTP proxy support is built-in as well. 15 | 16 | - easy to use 17 | - supports timeout 18 | - supports SSL (optional, currently using openssl or cyassl backend) 19 | - supports chaining of socks4/4a/5 proxies a la proxychains. 20 | the maximum number of proxies can be configured at compiletime. 21 | using a single proxy works as well, of course. 22 | - no global state (except for ssl init routines) 23 | - error reporting mechanism, showing the exact type 24 | - supports DNS resolving (can be turned off for smaller size) 25 | - does not use malloc, and in the DNS-less profile, does not use 26 | any libc functions that could call it. 27 | (malloc typically adds at least 20KB to the binary size if 28 | statically linked). 29 | of course once you build it with ssl support, ssl will definitely 30 | make use of malloc(). 31 | you need to add NO_DNS_SUPPORT to your CFLAGS 32 | so nothing that can call malloc gets pulled in, if you want a 33 | minimal static binary (in that case you have to pass ipv4 34 | addresses in dotted notation). 35 | - optionally uses [libulz](https://github.com/rofl0r/libulz), 36 | a lightweight C library, featuring things like 37 | a snprintf replacement which doesnt include code for float 38 | handling. 39 | this can make a statically linked binary a couple dozen KB 40 | smaller if no particularly bloated libc internals are being 41 | used in other parts of linked-in code. 42 | so if you use any SSL implementation, you won't gain anything 43 | by using libulz. 44 | 45 | build: 46 | 47 | for a "default" build, for example for a distribution, just 48 | use ./configure && make as usual. 49 | 50 | advanced/customized build using RcB: 51 | 52 | write your app, include the rocksock header using 53 | a relative pathname, and then use the build tool 54 | [rcb](https://github.com/rofl0r/rcb) on your main 55 | C file, supplying all config options as CFLAGS. rcb will then 56 | automatically find all required translation units and throw them 57 | at once at the compiler, giving perfect opportunities for link-time 58 | optimization. 59 | 60 | typical tree structure: 61 | ``` 62 | myapp/ 63 | rocksock/ 64 | lib/ (libulz) 65 | ``` 66 | 67 | myapp/main.c: 68 | ```c 69 | /* tiny program to see if a specific port on a specific host 70 | is open for usage in shellscripts or similar. */ 71 | #include "../rocksock/rocksock.h" 72 | #include 73 | #include 74 | 75 | static void usage(void) { 76 | dprintf(2, "usage: prog ip port\n"); 77 | exit(1); 78 | } 79 | 80 | int main(int argc, char** argv) { 81 | if(argc != 3) usage(); 82 | rocksock s; 83 | rocksock_init(&s); 84 | rocksock_set_timeout(&s, 5000); 85 | int ret = rocksock_connect(&s, argv[1], atoi(argv[2]), 0); 86 | rocksock_clear(&s); 87 | return ret; 88 | } 89 | ``` 90 | 91 | ```sh 92 | $ cd myapp 93 | $ CFLAGS="-DUSE_SSL -flto -O3 -s -static" rcb main.c 94 | ``` 95 | 96 | -------------------------------------------------------------------------------- /examples/proxychk.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * author: rofl0r 4 | * 5 | * License: LGPL 2.1+ with static linking exception 6 | * 7 | * 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include "../rocksock.h" 18 | 19 | static int timeout; 20 | static char chk_host[512]; 21 | static int chk_host_port; 22 | 23 | static int scanHost(char* baseproxy, char* scanproxy) { 24 | rocksock skt; 25 | rocksock* soc = &skt; 26 | int ret; 27 | 28 | rs_proxy proxies[2]; 29 | 30 | rocksock_init(soc, proxies); 31 | rocksock_set_timeout(soc, timeout); 32 | if(baseproxy) 33 | if(rocksock_add_proxy_fromstring(soc, baseproxy)) 34 | return -1; 35 | if(rocksock_add_proxy_fromstring(soc, scanproxy)) 36 | return -1; 37 | 38 | if (!rocksock_connect(soc, chk_host, chk_host_port, 0)){ 39 | ret = 0; /* success */ 40 | } else { 41 | //printf("%s\n", soc->lasterror.errormsg); 42 | ret = -1; 43 | } 44 | 45 | rocksock_disconnect(soc); 46 | rocksock_clear(soc); 47 | 48 | return ret; 49 | } 50 | 51 | static int usage(const char *argv0) { 52 | dprintf(2, 53 | "proxy checker.\n" 54 | "%s options\n" 55 | "[-b type://[user:pass@]base_proxy_ip:port]\n" 56 | "[-t type]\n" 57 | "[-c check_ip:port]\n" 58 | "[-T timeout_in_millisec]\n" 59 | "\n" 60 | "read [type://]ips:port from STDIN\n" 61 | "if type is given, all ip:port tuples from STDIN won't need a prefix\n" 62 | "if base proxy is given, it will be used as first proxy\n" 63 | "timeout defaults to 1500.\n" 64 | "checkip:port defaults to cnn.com:80\n" 65 | "for every proxy that works, its address will be echoed to stdout\n" 66 | "exit code is 0 when last proxy worked\n\n" 67 | "example: echo 127.0.0.1:9050 | %s -t socks4 -T 2000\n" 68 | "example: echo socks5://user:pass@127.0.0.1:1080 | %s\n" 69 | "\nyou may want to use JOBFLOW or GNU parallel for speedy parallel checks\n" 70 | , argv0, argv0, argv0); 71 | return 1; 72 | } 73 | 74 | int main(int argc, char** argv) { 75 | int c; 76 | char *typestring = 0; 77 | char *baseproxy = 0; 78 | char *checkurl = "cnn.com:80"; 79 | timeout = 1500; 80 | 81 | while ((c = getopt(argc, argv, "c:T:b:t:")) != -1) { 82 | switch(c) { 83 | case 'c': 84 | checkurl = optarg; 85 | break; 86 | case 'T': 87 | timeout = atoi(optarg); 88 | break; 89 | case 't': 90 | if(!strcmp(optarg, "socks4")) ; 91 | else if(!strcmp(optarg, "socks5")) ; 92 | else if(!strcmp(optarg, "http")) ; 93 | else { 94 | dprintf(2, "invalid proxy type\n"); 95 | return 1; 96 | } 97 | typestring = optarg; 98 | break; 99 | case 'b': 100 | baseproxy = optarg; 101 | break; 102 | default: 103 | return usage(argv[0]); 104 | } 105 | } 106 | 107 | { 108 | char *p = strchr(checkurl, ':'); 109 | if(!p) return usage(argv[0]); 110 | 111 | size_t l = p-checkurl; 112 | strncpy(chk_host, checkurl, l); 113 | chk_host[l] = 0; 114 | chk_host_port = atoi(++p); 115 | } 116 | 117 | char buf[1024]; 118 | int ret = 0; 119 | while(fgets(buf, sizeof buf, stdin)) { 120 | char nb[1024+10], *p; 121 | if((p = strrchr(buf, '\n'))) 122 | *p = 0; 123 | if(*buf == 0 || *buf == '#') continue; 124 | snprintf(nb, sizeof nb, "%s%s%s", 125 | typestring ? typestring : "", 126 | typestring ? "://" : "", 127 | buf); 128 | if(0 == (ret = scanHost(baseproxy, nb))) 129 | printf("%s\n", nb); 130 | 131 | } 132 | return ret; 133 | } 134 | -------------------------------------------------------------------------------- /rocksock_cyassl.c: -------------------------------------------------------------------------------- 1 | /* 2 | * author: rofl0r (C) 2011 - 2013 3 | * License: LGPL 2.1+ with static linking exception 4 | */ 5 | 6 | #ifdef USE_CYASSL 7 | 8 | #include "rocksock_ssl_internal.h" 9 | #include "rocksock_internal.h" 10 | 11 | #include 12 | 13 | 14 | #ifndef ROCKSOCK_FILENAME 15 | #define ROCKSOCK_FILENAME __FILE__ 16 | #endif 17 | 18 | #pragma RcB2 LINK "-lwolfssl" 19 | 20 | void rocksock_init_ssl(void) { 21 | CyaSSL_Init(); 22 | //CyaSSL_Debugging_ON(); /* cyassl needs to be compiled with --enable-debug */ 23 | } 24 | 25 | void rocksock_free_ssl(void) { 26 | CyaSSL_Cleanup(); 27 | } 28 | 29 | const char* rocksock_ssl_strerror(rocksock *sock, int error) { 30 | return CyaSSL_ERR_reason_error_string(error); 31 | } 32 | 33 | #include 34 | int rocksock_ssl_send(rocksock* sock, char* buf, size_t sz) { 35 | int ret = CyaSSL_write(sock->ssl, buf, sz); 36 | if (ret < 0 && CyaSSL_get_error(sock->ssl, ret) == SSL_ERROR_WANT_WRITE) errno = EWOULDBLOCK; 37 | return ret; 38 | } 39 | 40 | int rocksock_ssl_recv(rocksock* sock, char* buf, size_t sz) { 41 | int ret = CyaSSL_read(sock->ssl, buf, sz); 42 | if (ret < 0 && CyaSSL_get_error(sock->ssl, ret) == SSL_ERROR_WANT_READ) errno = EWOULDBLOCK; 43 | return ret; 44 | } 45 | 46 | int rocksock_ssl_connect_fd(rocksock* sock) { 47 | sock->sslctx = CyaSSL_CTX_new(CyaSSLv23_client_method()); 48 | if (!sock->sslctx) { 49 | return rocksock_seterror(sock, RS_ET_OWN, RS_E_SSL_GENERIC, ROCKSOCK_FILENAME, __LINE__); 50 | } 51 | 52 | /* FIXME cyassl needs explicit passing of certificates 53 | however the location may vary by system. 54 | until resolved, certificate checks are disabled */ 55 | CyaSSL_CTX_set_verify(sock->sslctx, SSL_VERIFY_NONE, 0); 56 | 57 | sock->ssl = CyaSSL_new(sock->sslctx); 58 | if (!sock->ssl) { 59 | return rocksock_seterror(sock, RS_ET_OWN, RS_E_SSL_GENERIC, ROCKSOCK_FILENAME, __LINE__); 60 | } 61 | 62 | CyaSSL_set_fd(sock->ssl, sock->socket); 63 | //CyaSSL_set_using_nonblock(sock->ssl, 0); 64 | 65 | int ret = CyaSSL_connect(sock->ssl); 66 | if(ret != SSL_SUCCESS) { 67 | /* when CyaSSL_connect gets interrupted by a timeout, it reports LENGTH_ERROR instead of 68 | SSL_ERROR_WANT_READ as it's supposed to do (see cyassl github issue #65). 69 | since that value is not exported we can't catch it without hardcoding the value, so we will wait for a fix */ 70 | if((ret = CyaSSL_get_error(sock->ssl, ret)) == SSL_ERROR_WANT_READ) 71 | return rocksock_seterror(sock, RS_ET_OWN, RS_E_HIT_CONNECTTIMEOUT, ROCKSOCK_FILENAME, __LINE__); 72 | return rocksock_seterror(sock, RS_ET_SSL, ret, ROCKSOCK_FILENAME, __LINE__); 73 | } 74 | return 0; 75 | } 76 | 77 | void rocksock_ssl_free_context(rocksock *sock) { 78 | if(sock->ssl) { 79 | CyaSSL_shutdown(sock->ssl); 80 | CyaSSL_free(sock->ssl); 81 | CyaSSL_CTX_free(sock->sslctx); 82 | sock->ssl = 0; 83 | } 84 | } 85 | 86 | int rocksock_ssl_pending(rocksock *sock) { 87 | return CyaSSL_pending(sock->ssl); 88 | } 89 | 90 | int rocksock_ssl_peek(rocksock* sock, int *result) { 91 | int ret; 92 | char buf[4]; 93 | ret = CyaSSL_peek(sock->ssl, buf, 1); 94 | if(ret >= 0) *result = 1; 95 | else { 96 | ret = CyaSSL_get_error(sock->ssl, 0); 97 | if(ret == SSL_ERROR_WANT_READ) return rocksock_seterror(sock, RS_ET_OWN, RS_E_HIT_READTIMEOUT, ROCKSOCK_FILENAME, __LINE__); 98 | return rocksock_seterror(sock, RS_ET_SSL, ret, ROCKSOCK_FILENAME, __LINE__); 99 | } 100 | return rocksock_seterror(sock, RS_ET_OWN, 0, NULL, 0); 101 | } 102 | 103 | #endif 104 | 105 | -------------------------------------------------------------------------------- /configure: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | #set -x 3 | prefix=/usr/local 4 | 5 | libs=`cat << EOF 6 | EOF 7 | ` 8 | clear_config() { 9 | rm -f config.mak 2>/dev/null 10 | } 11 | 12 | add_config() { 13 | printf "%s\n" "$1" >> config.mak 14 | } 15 | 16 | add_cflags() { 17 | add_config "CFLAGS += $1" 18 | } 19 | 20 | add_ldflags() { 21 | add_config "LDFLAGS += $1" 22 | } 23 | 24 | get_pkgconf_cflags() { 25 | pkg-config --cflags "$1" 2>/dev/null 26 | } 27 | 28 | get_pkgconf_ldflags() { 29 | pkg-config --libs "$1" 2>/dev/null 30 | } 31 | 32 | add_pkgconf_cflags() { 33 | fallback="$2" 34 | flags=$(get_pkgconf_cflags "$1") 35 | [ -z "$flags" ] && flags="$fallback" 36 | add_cflags "$flags" 37 | } 38 | 39 | add_pkgconf_ldflags() { 40 | fallback="$2" 41 | flags=$(get_pkgconf_ldflags "$1") 42 | [ -z "$flags" ] && flags="$fallback" 43 | add_ldflags "$flags" 44 | } 45 | 46 | add_lib() { 47 | add_pkgconf_cflags "$1" "$2" 48 | add_pkgconf_ldflags "$1" "$3" 49 | return 0 50 | } 51 | 52 | usage() { 53 | echo "supported arguments" 54 | echo "--prefix=/path default: $prefix" 55 | echo "--exec_prefix=/path default: $prefix/bin" 56 | echo "--bindir=/path default: $prefix/bin" 57 | echo "--libdir=/path default: $prefix/lib" 58 | echo "--includedir=/path default: $prefix/include" 59 | echo "--sysconfdir=/path default: $prefix/etc" 60 | echo "--with-ssl=[auto,wolfssl,openssl,no] default: auto" 61 | echo "--disable-static default: no" 62 | echo "--enable-shared default: no" 63 | echo "--help : show this text" 64 | exit 1 65 | } 66 | 67 | spliteq() { 68 | arg=$1 69 | echo "${arg#*=}" 70 | #alternatives echo "$arg" | cut -d= -f2- 71 | # or echo "$arg" | sed 's/[^=]*=//' 72 | } 73 | 74 | trylink () { 75 | printf "checking whether linking against %s works... " "$2" 76 | echo "int main(){};" > "$tmpc" 77 | if $CC "$2" -o /dev/null "$tmpc" >/dev/null 2>&1 ; then 78 | printf "yes\n" 79 | eval "$1=\"\${$1} \$2\"" 80 | eval "$1=\${$1# }" 81 | return 0 82 | else 83 | printf "no\n" 84 | return 1 85 | fi 86 | } 87 | 88 | ssl_lib=auto 89 | parsearg() { 90 | case "$1" in 91 | --prefix=*) prefix=`spliteq $1`;; 92 | --exec_prefix=*) exec_prefix=`spliteq $1`;; 93 | --bindir=*) bindir=`spliteq $1`;; 94 | --libdir=*) libdir=`spliteq $1`;; 95 | --includedir=*) includedir=`spliteq $1`;; 96 | --sysconfdir=*) sysconfdir=`spliteq $1`;; 97 | --help) usage;; 98 | --disable-static) disable_static=1 ;; 99 | --disable-static=yes) disable_static=1 ;; 100 | --enable-shared) enable_shared=1 ;; 101 | --enable-shared=yes) enable_shared=1 ;; 102 | --with-ssl=*) ssl_lib=`spliteq $1`;; 103 | esac 104 | } 105 | 106 | while true ; do 107 | case $1 in 108 | -*) parsearg "$1"; shift;; 109 | *) break ;; 110 | esac 111 | done 112 | 113 | [ -z "$exec_prefix" ] && exec_prefix=$prefix 114 | [ -z "$libdir" ] && libdir=$prefix/lib 115 | [ -z "$includedir" ] && includedir=$prefix/include 116 | [ -z "$sysconfdir" ] && sysconfdir=$prefix/etc 117 | [ -z "$bindir" ] && bindir=$exec_prefix/bin 118 | [ -z "$CC" ] && CC=cc 119 | 120 | clear_config 121 | 122 | add_config "prefix = $prefix" 123 | add_config "exec_prefix = $exec_prefix" 124 | add_config "bindir = $bindir" 125 | add_config "libdir = $libdir" 126 | add_config "includedir = $includedir" 127 | add_config "sysconfdir = $sysconfdir" 128 | 129 | add_config "CC ?= $CC" 130 | [ -z "$CPPFLAGS" ] || add_config "CPPFLAGS += $CPPFLAGS" 131 | [ -z "$CFLAGS" ] || add_cflags "$CFLAGS" 132 | 133 | for lib in $libs ; do add_lib "$lib" ; done 134 | 135 | # 136 | # Get a temp filename we can use 137 | # 138 | i=0 139 | set -C 140 | while : ; do i=$(($i+1)) 141 | tmpc="./conf$$-$PPID-$i.c" 142 | 2>|/dev/null > "$tmpc" && break 143 | test "$i" -gt 50 && fail "$0: cannot create temporary file $tmpc" 144 | done 145 | set +C 146 | trap 'rm "$tmpc"' EXIT INT QUIT TERM HUP 147 | 148 | 149 | if [ "$ssl_lib" = auto ] ; then 150 | foo= 151 | if trylink foo "-lwolfssl" ; then ssl_lib=cyassl 152 | elif trylink foo "-lssl" && trylink foo "-lcrypto" ; then ssl_lib=openssl 153 | else ssl_lib=no 154 | fi 155 | fi 156 | if [ ! "$ssl_lib" = no ] ; then 157 | add_config "CFLAGS += -DUSE_SSL" 158 | case "$ssl_lib" in 159 | openssl) add_lib openssl "" "-lssl -lcrypto" && add_cflags "-DUSE_OPENSSL" ;; 160 | cyassl|wolfssl) add_lib wolfssl "" "-lwolfssl" && add_cflags "-DUSE_CYASSL" ;; 161 | *) echo "error: unsupported --with-ssl option $ssl_lib" ; exit 1 ;; 162 | esac 163 | fi 164 | [ "$disable_static" = 1 ] && add_config "ALL_LIBS =" && enable_shared=1 165 | [ "$enable_shared" = 1 ] && add_config "ALL_LIBS += librocksock.so" 166 | 167 | 168 | echo "hint: if you intend to build a static binary with minimal size, try NO_DNS_SUPPORT in CFLAGS" 169 | echo "config.mak successfully created. now run make && make install" 170 | 171 | -------------------------------------------------------------------------------- /examples/portscanner.c: -------------------------------------------------------------------------------- 1 | // use rcb to compile: rcb portscanner.c 2 | 3 | /* 4 | * 5 | * author: rofl0r 6 | * 7 | * License: LGPL 2.1+ with static linking exception 8 | * 9 | * 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include "../rocksock.h" 20 | 21 | #pragma RcB2 LINK "-lpthread" 22 | 23 | typedef struct { 24 | char host[16]; 25 | int port; 26 | int status; 27 | } threaddata; 28 | 29 | static int done = 0; 30 | static pthread_mutex_t mutex; 31 | 32 | static void* scanHost(void* arg) { 33 | threaddata* d = arg; 34 | rocksock skt; 35 | rocksock* soc = &skt; 36 | rs_proxy proxies[1] = {0}; 37 | rocksock_init(soc, proxies); 38 | rocksock_set_timeout(soc, 1500); 39 | 40 | if (!rocksock_connect(soc, d->host, d->port, 0)){ 41 | d->status = 1; 42 | } else { 43 | //printf("%s\n", soc->lasterror.errormsg); 44 | d->status = 0; 45 | } 46 | 47 | rocksock_disconnect(soc); 48 | rocksock_clear(soc); 49 | 50 | pthread_mutex_lock(&mutex); 51 | done++; 52 | pthread_mutex_unlock(&mutex); 53 | return 0; 54 | } 55 | 56 | int running(pthread_t* t, int max) { 57 | int res = 0, i = 0; 58 | for (; i <= max; i++) { 59 | if (t[i]) res++; 60 | } 61 | return res; 62 | } 63 | 64 | int joinThreads(pthread_t* threads, int max) { 65 | void* exitstate; 66 | int i = 0; 67 | for(;i 254 ? 254 : max_threads; 81 | pthread_t threads[255] = {0}; 82 | threaddata data[255] = {0}; 83 | 84 | pthread_attr_t attr; 85 | size_t stack; 86 | pthread_attr_init(&attr); 87 | pthread_attr_getstacksize(&attr, &stack); 88 | stack = 32768; 89 | pthread_attr_setstacksize(&attr, stack); 90 | 91 | pthread_mutex_init(&mutex, NULL); 92 | 93 | volatile int x = 1; 94 | while(done < 254) { 95 | while(x < 255 && running((pthread_t*) threads, x) < maxthreads) { 96 | threaddata* d = &data[x]; 97 | snprintf(d->host, sizeof(d->host), "%s.%d", ip, x); 98 | d->port = port; 99 | d->status = -1; 100 | if (!pthread_create(&threads[x], &attr, scanHost, &data[x])) { 101 | x++; 102 | } 103 | else { 104 | break; 105 | } 106 | } 107 | joinThreads(threads, x); 108 | } 109 | 110 | joinThreads(threads, x); 111 | 112 | pthread_attr_destroy(&attr); 113 | 114 | int i = 0; 115 | for (; i < 255; i++) { 116 | if (data[i].status > 0) dprintf(1, "%s\n", data[i].host); 117 | } 118 | 119 | pthread_mutex_destroy(&mutex); 120 | return 0; 121 | } 122 | 123 | 124 | int scanPortRange(const char *ip, int sport, int eport, int max_threads) { 125 | 126 | int maxthreads = max_threads > 254 ? 254 : max_threads; 127 | int n_ports = eport - sport; 128 | pthread_t threads[255] = {0}; 129 | threaddata data[255] = {0}; 130 | 131 | pthread_attr_t attr; 132 | size_t stack; 133 | pthread_attr_init(&attr); 134 | pthread_attr_getstacksize(&attr, &stack); 135 | stack = 32768; 136 | pthread_attr_setstacksize(&attr, stack); 137 | 138 | pthread_mutex_init(&mutex, NULL); 139 | 140 | int currport = sport, i; 141 | while(done < n_ports) { 142 | int zero = 0; 143 | for(i = 0; i < maxthreads; ++i) { 144 | volatile threaddata* d = &data[i]; 145 | if(!threads[i]) { 146 | if(currport >= eport) { 147 | ++zero; 148 | continue; 149 | } 150 | memset(d, 0, sizeof *d); 151 | snprintf(d->host, sizeof(d->host), "%s", ip); 152 | d->port = currport++; 153 | d->status = -1; 154 | pthread_create(&threads[i], &attr, scanHost, &data[i]); 155 | } else { 156 | if(d->status != -1) { 157 | pthread_join(threads[i], 0); 158 | threads[i] = 0; 159 | if(d->status == 1) 160 | printf("port open: %d\n", d->port); 161 | } 162 | } 163 | } 164 | if(zero == maxthreads) break; 165 | usleep(50); 166 | } 167 | 168 | pthread_attr_destroy(&attr); 169 | pthread_mutex_destroy(&mutex); 170 | return 0; 171 | } 172 | 173 | 174 | int main(int argc, char** argv) { 175 | if (argc < 4) { 176 | syntax:; 177 | dprintf(2, "multithreaded portscanner\n" 178 | "invalid syntax\n\n" 179 | "-subnet single port mode:\n" 180 | "%s 127.0.0 22 16\n" 181 | "subnetA port maxthreads\n\n" 182 | "-single host multi-port mode:\n" 183 | "%s 127.0.0.1 portlist 16\n" 184 | "ip portlist maxthreads\n" 185 | "portlist specified as start-end in decimals\n", 186 | argv[0], argv[0]); 187 | return 1; 188 | } 189 | char* ip = argv[1], *p = ip; 190 | int n = 0; 191 | while(*p) if(*(p++) == '.') ++n; 192 | if(n < 2 || n > 3) goto syntax; 193 | int maxthreads = atoi(argv[3]); 194 | if(n == 2) { 195 | int port = atoi(argv[2]); 196 | scanRange(ip, port, maxthreads); 197 | return 0; 198 | } 199 | int startport = atoi(argv[2]); 200 | if(!(p = strchr(argv[2], '-'))) goto syntax; 201 | int endport = atoi(++p); 202 | return scanPortRange(ip, startport, endport, maxthreads); 203 | } 204 | -------------------------------------------------------------------------------- /rocksock.h: -------------------------------------------------------------------------------- 1 | /* 2 | * author: rofl0r 3 | * License: LGPL 2.1+ with static linking exception 4 | */ 5 | 6 | #ifndef _ROCKSOCK_H_ 7 | #define _ROCKSOCK_H_ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | typedef enum { 15 | RS_PT_NONE = 0, 16 | RS_PT_SOCKS4, 17 | RS_PT_SOCKS5, 18 | RS_PT_HTTP 19 | } rs_proxyType; 20 | 21 | typedef enum rs_errorType { 22 | RS_ET_OWN = 0, 23 | RS_ET_SYS, 24 | RS_ET_GAI, 25 | RS_ET_SSL, 26 | RS_ET_MAX 27 | } rs_errorType; 28 | 29 | typedef enum rs_error { 30 | RS_E_NO_ERROR = 0, 31 | RS_E_NULL = 1, 32 | RS_E_EXCEED_PROXY_LIMIT = 2, 33 | RS_E_NO_SSL = 3, 34 | RS_E_NO_SOCKET = 4, 35 | RS_E_HIT_TIMEOUT = 5, 36 | RS_E_OUT_OF_BUFFER = 6, 37 | RS_E_SSL_GENERIC = 7, 38 | RS_E_SOCKS4_NOAUTH = 8, 39 | RS_E_SOCKS5_AUTH_EXCEEDSIZE = 9, 40 | RS_E_SOCKS4_NO_IP6 = 10, 41 | RS_E_PROXY_UNEXPECTED_RESPONSE = 11, 42 | RS_E_TARGETPROXY_CONNECT_FAILED = 12, 43 | RS_E_PROXY_AUTH_FAILED = 13, 44 | RS_E_HIT_READTIMEOUT = 14, 45 | RS_E_HIT_WRITETIMEOUT = 15, 46 | RS_E_HIT_CONNECTTIMEOUT = 16, 47 | RS_E_PROXY_GENERAL_FAILURE = 17, 48 | RS_E_TARGETPROXY_NET_UNREACHABLE = 18, 49 | RS_E_TARGETPROXY_HOST_UNREACHABLE = 19, 50 | RS_E_TARGETPROXY_CONN_REFUSED = 20, 51 | RS_E_TARGETPROXY_TTL_EXPIRED = 21, 52 | RS_E_PROXY_COMMAND_NOT_SUPPORTED = 22, 53 | RS_E_PROXY_ADDRESSTYPE_NOT_SUPPORTED = 23, 54 | RS_E_REMOTE_DISCONNECTED = 24, 55 | RS_E_NO_PROXYSTORAGE = 25, 56 | RS_E_HOSTNAME_TOO_LONG = 26, 57 | RS_E_INVALID_PROXY_URL = 27, 58 | RS_E_MAX_ERROR = 28 59 | } rs_error; 60 | 61 | typedef struct { 62 | rs_errorType errortype; 63 | int error; 64 | int line; 65 | const char* file; 66 | int failedProxy; 67 | } rs_errorInfo; 68 | 69 | typedef struct { 70 | char host[256]; 71 | unsigned short port; 72 | } rs_hostInfo; 73 | 74 | typedef struct { 75 | char username[256]; 76 | char password[256]; 77 | rs_hostInfo hostinfo; 78 | rs_proxyType proxytype; 79 | } rs_proxy; 80 | 81 | typedef struct rocksock { 82 | int socket; 83 | int connected; 84 | unsigned long timeout; 85 | rs_proxy *proxies; 86 | ptrdiff_t lastproxy; 87 | rs_errorInfo lasterror; 88 | void *ssl; 89 | void *sslctx; 90 | } rocksock; 91 | 92 | #ifdef __cplusplus 93 | extern "C" { 94 | #endif 95 | 96 | void rocksock_init_ssl(void); 97 | void rocksock_free_ssl(void); 98 | 99 | /* all rocksock functions that return int return 0 on success or an errornumber on failure */ 100 | /* rocksock_init: pass empty rocksock struct and if you want to use proxies, 101 | an array of rs_proxy's that you need to allocate yourself. */ 102 | int rocksock_init(rocksock* sock, rs_proxy *proxies); 103 | int rocksock_set_timeout(rocksock* sock, unsigned long timeout_millisec); 104 | int rocksock_add_proxy(rocksock* sock, rs_proxyType proxytype, const char* host, unsigned short port, const char* username, const char* password); 105 | int rocksock_add_proxy_fromstring(rocksock* sock, const char *proxystring); 106 | int rocksock_connect(rocksock* sock, const char* host, unsigned short port, int useSSL); 107 | int rocksock_send(rocksock* sock, char* buffer, size_t bufsize, size_t chunksize, size_t* byteswritten); 108 | int rocksock_recv(rocksock* sock, char* buffer, size_t bufsize, size_t chunksize, size_t* bytesread); 109 | int rocksock_readline(rocksock* sock, char* buffer, size_t bufsize, size_t* bytesread); 110 | int rocksock_disconnect(rocksock* sock); 111 | 112 | /* returns a string describing the last error or NULL */ 113 | const char* rocksock_strerror(rocksock *sock); 114 | /* return a string describing in which subsytem the last error happened, or NULL */ 115 | const char* rocksock_strerror_type(rocksock *sock); 116 | /* return a string describing the last error, and which proxy caused it */ 117 | char* rocksock_strerror_detailed(rocksock *sock, char *msgbuf, size_t buflen); 118 | 119 | enum rs_errorType rocksock_get_errortype(rocksock *sock); 120 | int rocksock_get_error(rocksock *sock); 121 | 122 | #define rocksock_error_dprintf(FD, RS) \ 123 | dprintf(FD, "%s:%d - %s error: %s from %s:%d\n", \ 124 | __FILE__, __LINE__, rocksock_strerror_type(RS), rocksock_strerror(RS), \ 125 | (RS)->lasterror.file, (RS)->lasterror.line) 126 | 127 | /* clears/free's/resets all internally used buffers. etc but doesn't free the rocksock itself, since it could be stack-alloced */ 128 | int rocksock_clear(rocksock* sock); 129 | /* check if data is available for read. result will contain 1 if available, 0 if not available. 130 | return value 0 indicates success, everything else error. result may not be NULL */ 131 | int rocksock_peek(rocksock* sock, int *result); 132 | 133 | /* using these two pulls in malloc from libc - only matters if you static link and dont use SSL */ 134 | /* returns a new heap alloced rocksock object which must be passed to rocksock_init later on */ 135 | rocksock* rocksock_new(void); 136 | /* free *only* the rocksock object. typically you would call rocksock_clear first */ 137 | void rocksock_free(rocksock* s); 138 | 139 | #ifdef __cplusplus 140 | } 141 | #endif 142 | 143 | #endif 144 | 145 | #pragma RcB2 DEP "rocksock.c" 146 | #pragma RcB2 DEP "rocksock_add_proxy.c" 147 | #pragma RcB2 DEP "rocksock_add_proxy_fromstring.c" 148 | #pragma RcB2 DEP "rocksock_error.c" 149 | #pragma RcB2 DEP "rocksock_strerror.c" 150 | #pragma RcB2 DEP "rocksock_strerror_type.c" 151 | #pragma RcB2 DEP "rocksock_strerror_detailed.c" 152 | #pragma RcB2 DEP "rocksock_dynamic.c" 153 | #pragma RcB2 DEP "rocksock_readline.c" 154 | #pragma RcB2 DEP "rocksock_peek.c" 155 | #pragma RcB2 DEP "rocksock_ssl.c" 156 | 157 | -------------------------------------------------------------------------------- /examples/proxychain.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * author: rofl0r 4 | * 5 | * License: LGPL 2.1+ with static linking exception 6 | * 7 | * 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include "../rocksock.h" 18 | #include "../../lib/include/stringlist.h" 19 | 20 | static int timeout; 21 | static char chk_host[512]; 22 | static int chk_host_port; 23 | static int debug = 1; 24 | 25 | #define DPRINTF(fmt, args...) if(debug) do { dprintf(2,fmt, ## args); } while(0) 26 | 27 | static int scanHost(stringlist* chain, char* scanproxy, size_t max, rs_errorInfo *e_info) { 28 | rocksock skt; 29 | rocksock* soc = &skt; 30 | int ret; 31 | 32 | rs_proxy proxies[stringlist_getsize(chain)+1]; 33 | 34 | rocksock_init(soc, proxies); 35 | rocksock_set_timeout(soc, timeout); 36 | 37 | DPRINTF("====== checking %s (timeout: %d)\n", scanproxy, timeout); 38 | 39 | size_t i, top = max == -1 ? stringlist_getsize(chain) : max; 40 | char *candidate; 41 | for(i = 0; i < top; i++) { 42 | // stringlist_foreach(chain, candidate) { 43 | candidate = stringlist_get(chain, i); 44 | DPRINTF("> %s\n", candidate); 45 | if(rocksock_add_proxy_fromstring(soc, candidate)) 46 | return -1; 47 | } 48 | 49 | if(rocksock_add_proxy_fromstring(soc, scanproxy)) 50 | return -1; 51 | 52 | if (!rocksock_connect(soc, chk_host, chk_host_port, 0)){ 53 | DPRINTF("SUCCESS\n"); 54 | ret = 0; /* success */ 55 | } else { 56 | char ebuf[256]; 57 | DPRINTF("%s\n", rocksock_strerror_detailed(soc, ebuf, sizeof ebuf)); 58 | *e_info = soc->lasterror; 59 | ret = -1; 60 | } 61 | 62 | rocksock_disconnect(soc); 63 | rocksock_clear(soc); 64 | 65 | return ret; 66 | } 67 | 68 | static int usage(const char *argv0) { 69 | dprintf(2, 70 | "proxy checker/chain generator.\n\n" 71 | 72 | "%s [options] chain-length\n" 73 | "[-c check_ip:port]\n" 74 | "[-T global timeout_in_millisec]\n" 75 | "[-t per-proxy additional timeout_in_millisec]\n" 76 | "[-l fixedlist.txt]\n" 77 | "\n" 78 | 79 | "generates a working proxychain.\n" 80 | "every proxy that works will be added to the chain, and connects will only\n" 81 | "be done through the existing chain.\n" 82 | "if the desired chain length is reached, the chain will be printed to stdout.\n" 83 | "the list of proxies is passed on stdin in type://ip:port format, where type\n" 84 | "can be one of socks4|socks5|http\n" 85 | "the optional list added with -l contains proxies that will be added w/o check\n" 86 | "\n" 87 | 88 | "timeout defaults to 1500.\n" 89 | "checkip:port defaults to cnn.com:80\n" 90 | 91 | ,argv0, argv0, argv0); 92 | return 1; 93 | } 94 | 95 | int main(int argc, char** argv) { 96 | int c; 97 | char *typestring = 0; 98 | char *baseproxy = 0; 99 | char *load_list = 0; 100 | char *checkurl = "cnn.com:80"; 101 | int base_timeout = 1500; 102 | int per_proxy_timeout = 0; 103 | 104 | while ((c = getopt(argc, argv, "c:T:t:l:")) != -1) { 105 | switch(c) { 106 | case 'c': 107 | checkurl = optarg; 108 | break; 109 | case 'T': 110 | base_timeout = atoi(optarg); 111 | break; 112 | case 't': 113 | per_proxy_timeout = atoi(optarg); 114 | break; 115 | case 'l': 116 | load_list = optarg; 117 | break; 118 | default: 119 | return usage(argv[0]); 120 | } 121 | } 122 | 123 | if (optind >= argc) { 124 | dprintf(2, "error: chain length missing\n"); 125 | return usage(argv[0]); 126 | } 127 | 128 | int n_proxies = atoi(argv[optind]); 129 | 130 | { 131 | char *p = strchr(checkurl, ':'); 132 | if(!p) return usage(argv[0]); 133 | 134 | size_t l = p-checkurl; 135 | strncpy(chk_host, checkurl, l); 136 | chk_host[l] = 0; 137 | chk_host_port = atoi(++p); 138 | } 139 | 140 | 141 | stringlist *chain = stringlist_new(n_proxies); 142 | 143 | char buf[1024]; 144 | if(load_list) { 145 | FILE *f = fopen(load_list, "r"); 146 | while(fgets(buf, sizeof buf, f)) { 147 | char *p; 148 | if((p = strrchr(buf, '\n'))) *p = 0; 149 | if(*buf == 0 || *buf == '#') continue; 150 | stringlist_add_dup(chain, buf); 151 | } 152 | } 153 | 154 | int ret = 0; 155 | while(stringlist_getsize(chain) < n_proxies) { 156 | if(!fgets(buf, sizeof buf, stdin)) 157 | return 1; 158 | char *p; 159 | if((p = strrchr(buf, '\n'))) *p = 0; 160 | if(*buf == 0 || *buf == '#') continue; 161 | 162 | size_t i; 163 | for(i=0; i < stringlist_getsize(chain); i++) { 164 | char *entry = stringlist_get(chain, i); 165 | if (!strcmp(entry, buf)) goto next; 166 | } 167 | 168 | timeout = base_timeout + (per_proxy_timeout * stringlist_getsize(chain)); 169 | rs_errorInfo last_err; 170 | if(0 == (ret = scanHost(chain, buf, -1, &last_err))) 171 | stringlist_add_dup(chain, buf); 172 | else { 173 | if(last_err.errortype == RS_ET_OWN && 174 | (last_err.error == RS_E_REMOTE_DISCONNECTED || 175 | last_err.error == RS_E_TARGETPROXY_CONN_REFUSED) && 176 | last_err.failedProxy != -1 && stringlist_getsize(chain) > 0 177 | ) { 178 | int fp = last_err.failedProxy, fails = 0; 179 | for(i=0; i<3; i++) { 180 | ret = scanHost(chain, buf, fp, &last_err); 181 | if(!ret || last_err.failedProxy != fp) break; 182 | fails++; 183 | } 184 | if(fails > 2) { 185 | dprintf(2, "proxy: %d stopped working, removing\n", fp); 186 | stringlist_delete(chain, fp); 187 | } 188 | } 189 | } 190 | next:; 191 | } 192 | char *px; 193 | stringlist_foreach(chain, px) { 194 | printf("%s\n", px); 195 | } 196 | return ret; 197 | } 198 | -------------------------------------------------------------------------------- /examples/micserver.c: -------------------------------------------------------------------------------- 1 | /* 2 | * author: rofl0r 3 | * 4 | * License: LGPL 2.1+ with static linking exception 5 | 6 | * soundplay server: waits for a client to connect, 7 | * then passes stream received to audio hardware. 8 | * designed to stream microphone input from one computer to 9 | * the other. 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "micbuffer.h" 19 | 20 | #include "../rocksockserver.h" 21 | 22 | 23 | //RcB: CFLAGS "-std=c99 -D_GNU_SOURCE -DVERBOSE" 24 | //RcB: LINK "-lasound -lpthread" 25 | 26 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) 27 | #define MICSERVER_NUMBUFFERS 20 28 | 29 | #ifdef VERBOSE 30 | #define DPRINTF(fd, ...) dprintf(fd, __VA_ARGS__) 31 | #else 32 | #define DPRINTF(fd, ...) 33 | #endif 34 | 35 | typedef struct client { 36 | int fd; 37 | unsigned char wave[MICSERVER_NUMBUFFERS][MIC_BUFFER_SIZE]; 38 | unsigned long long samples_recvd; 39 | unsigned long long samples_consumed; 40 | snd_pcm_t *playback_handle; 41 | pthread_mutex_t mtx; 42 | pthread_t thr; 43 | int terminate; 44 | } client; 45 | 46 | typedef struct server_state { 47 | rocksockserver srv; 48 | const char* audiodevice; 49 | } server; 50 | 51 | static struct progstate { 52 | server s; 53 | client client; 54 | } p; 55 | 56 | static void disconnect_client(server* s, int fd) { 57 | if(p.client.fd == fd) { 58 | struct client* c = &p.client; 59 | c->terminate = -1; 60 | pthread_join(c->thr, 0); 61 | snd_pcm_close(c->playback_handle); 62 | c->fd = -1; 63 | } 64 | rocksockserver_disconnect_client(&s->srv, fd); 65 | } 66 | 67 | static int on_cdisconnect (void* userdata, int fd) { 68 | server* s = userdata; 69 | disconnect_client(s, fd); 70 | return 0; 71 | } 72 | 73 | static const char* getstatus_string(snd_pcm_state_t status) { 74 | switch (status) { 75 | case SND_PCM_STATE_PAUSED: 76 | return "SND_PCM_STATE_PAUSED"; 77 | case SND_PCM_STATE_SETUP: 78 | return "SND_PCM_STATE_SETUP"; 79 | case SND_PCM_STATE_PREPARED: 80 | return "SND_PCM_STATE_PREPARED"; 81 | case SND_PCM_STATE_SUSPENDED: 82 | return "SND_PCM_STATE_SUSPENDED"; 83 | case SND_PCM_STATE_DISCONNECTED: 84 | return "SND_PCM_STATE_DISCONNECTED"; 85 | case SND_PCM_STATE_XRUN: 86 | return "SND_PCM_STATE_XRUN"; 87 | case SND_PCM_STATE_DRAINING: 88 | return "SND_PCM_STATE_DRAINING"; 89 | case SND_PCM_STATE_RUNNING: 90 | return "SND_PCM_STATE_RUNNING"; 91 | default: 92 | return "UNKNOWN"; 93 | } 94 | } 95 | 96 | static void chk(const int err, const char* msg) { 97 | if(err < 0) { 98 | dprintf(2, msg, snd_strerror(err)); 99 | exit(1); 100 | } 101 | } 102 | 103 | static snd_pcm_t* init_playback_device(const char* devname) { 104 | snd_pcm_t *playback_handle; 105 | snd_pcm_hw_params_t *hw_params; 106 | chk(snd_pcm_open(&playback_handle, devname, SND_PCM_STREAM_PLAYBACK,0), "cannot open audio device (%s)\n"); 107 | chk(snd_pcm_hw_params_malloc(&hw_params), "cannot allocate hardware parameter structure (%s)\n"); 108 | chk(snd_pcm_hw_params_any(playback_handle, hw_params), "cannot initialize hardware parameter structure (%s)\n"); 109 | chk(snd_pcm_hw_params_set_access(playback_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED), "cannot set access type (%s)\n"); 110 | chk(snd_pcm_hw_params_set_format(playback_handle, hw_params, FORMAT), "cannot set sample format (%s)\n"); 111 | unsigned rate = BITRATE; 112 | chk(snd_pcm_hw_params_set_rate_near(playback_handle, hw_params, &rate, 0), "cannot set sample rate (%s)\n"); 113 | chk(snd_pcm_hw_params_set_channels(playback_handle, hw_params, NUMCHANNELS),"cannot set channel count (%s)\n"); 114 | chk(snd_pcm_hw_params(playback_handle, hw_params), "cannot set parameters (%s)\n"); 115 | snd_pcm_hw_params_free(hw_params); 116 | chk(snd_pcm_prepare(playback_handle), "cannot prepare audio interface for use (%s)\n"); 117 | return playback_handle; 118 | } 119 | 120 | static unsigned long long get_recvd(client *c) { 121 | unsigned long long l; 122 | pthread_mutex_lock(&c->mtx); 123 | l = c->samples_recvd; 124 | pthread_mutex_unlock(&c->mtx); 125 | return l; 126 | } 127 | 128 | static void play(snd_pcm_t *playback_handle, const unsigned char* buf, size_t s) { 129 | int ret = snd_pcm_writei(playback_handle, buf, s); 130 | if (ret<0) { 131 | DPRINTF(2, "write to audio interface failed (%s)\n", snd_strerror(ret)); 132 | snd_pcm_state_t state = snd_pcm_state(playback_handle); 133 | DPRINTF(2, "%s\n", getstatus_string(state)); 134 | if(state == SND_PCM_STATE_XRUN) snd_pcm_recover(playback_handle, ret, 1); 135 | } 136 | } 137 | 138 | static void *c_thread(void *userdata) { 139 | client *c = userdata; 140 | while(!c->terminate) { 141 | if(get_recvd(c) - c->samples_consumed >= ARRAY_SIZE(c->wave)/2) { 142 | do { 143 | unsigned x = c->samples_consumed % ARRAY_SIZE(c->wave); 144 | DPRINTF(2, "playing samplebuf %u\n", x); 145 | play(c->playback_handle, c->wave[x], sizeof(c->wave[0])); 146 | c->samples_consumed++; 147 | } while(get_recvd(c) - c->samples_consumed > 0); 148 | } 149 | usleep(1); 150 | } 151 | return 0; 152 | } 153 | 154 | static int on_cconnect (void* userdata, struct sockaddr_storage* clientaddr, int fd) { 155 | (void) clientaddr; 156 | server* s = userdata; 157 | if(p.client.fd != -1) { 158 | disconnect_client(s, fd); 159 | return -1; 160 | } 161 | struct client* c = &p.client; 162 | c->fd = fd; 163 | c->terminate = 0; 164 | c->playback_handle = init_playback_device(s->audiodevice); 165 | pthread_mutex_init(&c->mtx, 0); 166 | pthread_create(&c->thr, 0, c_thread, c); 167 | return 0; 168 | } 169 | 170 | static int on_cread (void* userdata, int fd, size_t dummy) { 171 | (void) dummy; 172 | server* s = userdata; 173 | struct client *c = &p.client; 174 | unsigned x = c->samples_recvd % ARRAY_SIZE(c->wave); 175 | DPRINTF(2, "receiving samplebuf %u\n", x); 176 | if(sizeof(c->wave[0]) != recv(fd, c->wave[x], sizeof(c->wave[0]), 0)) { 177 | disconnect_client(s, fd); 178 | return 0; 179 | } 180 | pthread_mutex_lock(&c->mtx); 181 | c->samples_recvd++; 182 | pthread_mutex_unlock(&c->mtx); 183 | return 0; 184 | } 185 | 186 | static int on_cwantsdata (void* userdata, int fd) { 187 | server* s = userdata; 188 | return 0; 189 | } 190 | 191 | int main(int argc, char** argv) { 192 | server *s = &p.s; 193 | p.client.fd = -1; 194 | s->audiodevice = argc > 1 ? argv[1] : "default"; 195 | const int port = 9999; 196 | const char* listenip = "0.0.0.0"; 197 | if(rocksockserver_init(&s->srv, listenip, port, (void*) s)) return -1; 198 | rocksockserver_set_sleeptime(&s->srv, BITRATE); 199 | rocksockserver_set_perrorfunc(&s->srv, perror); 200 | if(rocksockserver_loop(&s->srv, NULL, 0, 201 | &on_cconnect, &on_cread, 202 | &on_cwantsdata, &on_cdisconnect)) return -2; 203 | return 0; 204 | } 205 | -------------------------------------------------------------------------------- /rocksockserver.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * author: rofl0r 4 | * 5 | * License: LGPL 2.1+ with static linking exception 6 | * 7 | * 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include "rocksockserver.h" 23 | 24 | #include "endianness.h" 25 | 26 | #define LOGP(X) do { if(srv->perr) srv->perr(X); } while(0) 27 | 28 | #ifdef USE_LIBULZ 29 | #include "../lib/include/strlib.h" 30 | #include "../lib/include/timelib.h" 31 | #else 32 | #include 33 | #include 34 | #define microsleep(X) usleep(X) 35 | static inline char* my_intToString(int i, char *b, size_t s) { 36 | int x = snprintf(b, s, "%d", i); 37 | if(x > 0 && x < s) return b; 38 | return 0; 39 | } 40 | #define intToString(i, b) my_intToString(i, b, sizeof(b)) 41 | #define ipv4fromstring(s, b) inet_aton(s, (struct in_addr *)(void*)(b)) 42 | #endif 43 | 44 | typedef struct { 45 | const char* host; 46 | unsigned short port; 47 | #ifndef IPV4_ONLY 48 | struct addrinfo* hostaddr; 49 | #else 50 | struct sockaddr_in hostaddr; 51 | #endif 52 | } rs_hostInfo; 53 | 54 | int rocksockserver_resolve_host(rs_hostInfo* hostinfo) { 55 | if (!hostinfo || !hostinfo->host || !hostinfo->port) return -1; 56 | #ifndef IPV4_ONLY 57 | char pbuf[8]; 58 | char* ports; 59 | int ret; 60 | struct addrinfo hints; 61 | 62 | memset(&hints, 0, sizeof(hints)); 63 | hints.ai_family = AF_UNSPEC; 64 | hints.ai_socktype = SOCK_STREAM; 65 | hints.ai_flags = AI_PASSIVE; 66 | if(!(ports = intToString(hostinfo->port, pbuf))) return -1; 67 | return getaddrinfo(hostinfo->host, ports, &hints, &hostinfo->hostaddr); 68 | #else 69 | memset(&hostinfo->hostaddr, 0, sizeof(struct sockaddr_in)); 70 | ipv4fromstring(hostinfo->host, (unsigned char*) &hostinfo->hostaddr.sin_addr); 71 | hostinfo->hostaddr.sin_family = AF_INET; 72 | hostinfo->hostaddr.sin_port = htons(hostinfo->port); 73 | return 0; 74 | #endif 75 | } 76 | 77 | /* returns 0 on success. 78 | possible error return codes: 79 | -1: erroneus parameter 80 | -2: bind() failed 81 | -3: socket() failed 82 | -4: listen() failed 83 | positive number: dns error, pass to gai_strerror() 84 | */ 85 | int rocksockserver_init(rocksockserver* srv, const char* listenip, unsigned short port, void* userdata) { 86 | int ret = 0; 87 | int yes = 1; 88 | rs_hostInfo conn; 89 | if(!srv || !listenip || !port) return -1; 90 | conn.host = listenip; 91 | conn.port = port; 92 | FD_ZERO(&srv->master); 93 | srv->userdata = userdata; 94 | srv->sleeptime_us = 20000; // set a reasonable default value. it's a compromise between throughput and cpu usage basically. 95 | ret = rocksockserver_resolve_host(&conn); 96 | if(ret) return ret; 97 | #ifndef IPV4_ONLY 98 | struct addrinfo* p; 99 | for(p = conn.hostaddr; p != NULL; p = p->ai_next) { 100 | srv->listensocket = socket(p->ai_family, p->ai_socktype, p->ai_protocol); 101 | if (srv->listensocket < 0) { 102 | continue; 103 | } 104 | 105 | // lose the pesky "address already in use" error message 106 | setsockopt(srv->listensocket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)); 107 | 108 | if (bind(srv->listensocket, p->ai_addr, p->ai_addrlen) < 0) { 109 | close(srv->listensocket); 110 | continue; 111 | } 112 | 113 | break; 114 | } 115 | if (!p) { 116 | LOGP("bind"); 117 | ret = -2; 118 | } 119 | freeaddrinfo(conn.hostaddr); 120 | if(ret == -2) return -2; 121 | #else 122 | srv->listensocket = socket(AF_INET, SOCK_STREAM, 0); 123 | if(srv->listensocket < 0) { 124 | LOGP("socket"); 125 | return -3; 126 | } 127 | setsockopt(srv->listensocket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)); 128 | if(bind(srv->listensocket, (struct sockaddr*) &conn.hostaddr, sizeof(struct sockaddr_in)) < 0) { 129 | close(srv->listensocket); 130 | LOGP("bind"); 131 | return -2; 132 | } 133 | 134 | #endif 135 | // listen 136 | if (listen(srv->listensocket, 10) == -1) { 137 | LOGP("listen"); 138 | ret = -4; 139 | } else { 140 | FD_SET(srv->listensocket, &srv->master); 141 | srv->maxfd = srv->listensocket; 142 | } 143 | return ret; 144 | } 145 | 146 | int rocksockserver_disconnect_client(rocksockserver* srv, int client) { 147 | if(client < 0 || client > USER_MAX_FD) return -1; 148 | if(FD_ISSET(client, &srv->master)) { 149 | close(client); 150 | FD_CLR(client, &srv->master); 151 | if(client == srv->maxfd) 152 | srv->maxfd--; 153 | srv->numfds--; 154 | return 0; 155 | } 156 | return 1; 157 | } 158 | 159 | void rocksockserver_watch_fd(rocksockserver* srv, int newfd) { 160 | FD_SET(newfd, &srv->master); 161 | if (newfd > srv->maxfd) 162 | srv->maxfd = newfd; 163 | } 164 | 165 | int rocksockserver_loop(rocksockserver* srv, 166 | char* buf, size_t bufsize, 167 | int (*on_clientconnect) (void* userdata, struct sockaddr_storage* clientaddr, int fd), 168 | int (*on_clientread) (void* userdata, int fd, size_t nread), 169 | int (*on_clientwantsdata) (void* userdata, int fd), 170 | int (*on_clientdisconnect) (void* userdata, int fd) 171 | ) { 172 | fd_set read_fds, write_fds; 173 | int newfd, k; 174 | int lastfd = 3; 175 | #ifdef IS_LITTLE_ENDIAN 176 | int i; 177 | size_t j; 178 | #endif 179 | ptrdiff_t nbytes; 180 | struct sockaddr_storage remoteaddr; // client address 181 | socklen_t addrlen; 182 | char* fdptr; 183 | fd_set* setptr; 184 | 185 | for(;;) { 186 | 187 | read_fds = srv->master; 188 | write_fds = srv->master; 189 | 190 | if ((srv->numfds = select(srv->maxfd+1, &read_fds, &write_fds, NULL, NULL)) && srv->numfds == -1) 191 | LOGP("select"); 192 | 193 | if(!srv->numfds) continue; 194 | 195 | // optimization for the case searched_fd = lastfd, when we only have to handle one connection. 196 | // i guess that should be the majority of cases. 197 | k = lastfd; 198 | setptr = &write_fds; 199 | if(FD_ISSET(k, setptr)) goto gotcha; 200 | setptr = &read_fds; 201 | if(FD_ISSET(k, setptr)) goto gotcha; 202 | 203 | nextfd: 204 | setptr = &write_fds; 205 | loopstart: 206 | fdptr = (char*) setptr; 207 | #ifdef IS_LITTLE_ENDIAN 208 | for(i = 0; i * CHAR_BIT <= srv->maxfd; i+= sizeof(size_t)) { // we assume that sizeof(fd_set) is a multiple of sizeof(size_t) 209 | if( *(size_t*)(fdptr + i)) { 210 | for(j = 0; j <= sizeof(size_t); j++) { 211 | if(fdptr[i + j]) { 212 | for(k = (i + j) * CHAR_BIT; k <= srv->maxfd; k++) { 213 | #else 214 | for(k = 0; k <= srv->maxfd; k++) { 215 | #endif 216 | if(FD_ISSET(k, setptr)) { 217 | gotcha: 218 | srv->numfds--; 219 | FD_CLR(k, setptr); 220 | if(setptr == &write_fds) 221 | goto handlewrite; 222 | else 223 | goto handleread; 224 | } 225 | } 226 | #ifdef IS_LITTLE_ENDIAN 227 | } 228 | } 229 | } 230 | } 231 | 232 | #endif 233 | 234 | if(setptr == &write_fds) { 235 | setptr = &read_fds; 236 | goto loopstart; 237 | } else { 238 | LOGP("FATAL"); 239 | /* 240 | printf("maxfd %d, k %d, numfds %d, set %d\n", srv->maxfd, k, srv->numfds, *(int*)(fdptr)); 241 | for(k = 0; k < USER_MAX_FD; k++) 242 | if(FD_ISSET(k, setptr)) 243 | printf("bit set: %d\n", k); 244 | */ 245 | return 1; 246 | } 247 | 248 | handleread: 249 | //printf("read_fd %d\n", k); 250 | if (k == srv->listensocket) { 251 | // new connection available 252 | addrlen = sizeof(remoteaddr); 253 | newfd = accept(srv->listensocket, (struct sockaddr *)&remoteaddr, &addrlen); 254 | 255 | if (newfd == -1) { 256 | LOGP("accept"); 257 | } else { 258 | if(newfd >= USER_MAX_FD) 259 | close(newfd); // only USER_MAX_FD connections can be handled. 260 | else { 261 | FD_SET(newfd, &srv->master); 262 | if (newfd > srv->maxfd) 263 | srv->maxfd = newfd; 264 | if(on_clientconnect) on_clientconnect(srv->userdata, &remoteaddr, newfd); 265 | } 266 | } 267 | } else { 268 | if(buf && k != srv->signalfd) { 269 | if ((nbytes = recv(k, buf, bufsize, 0)) <= 0) { 270 | if (nbytes == 0) { 271 | if(on_clientdisconnect) on_clientdisconnect(srv->userdata, k); 272 | } else { 273 | LOGP("recv"); 274 | } 275 | rocksockserver_disconnect_client(srv, k); 276 | } else { 277 | if(on_clientread) on_clientread(srv->userdata, k, nbytes); 278 | } 279 | } else { 280 | 281 | if(on_clientread) on_clientread(srv->userdata, k, 0); 282 | } 283 | } 284 | goto zzz; 285 | 286 | handlewrite: 287 | 288 | //printf("write_fd %d\n", k); 289 | if(on_clientwantsdata) on_clientwantsdata(srv->userdata, k); 290 | 291 | zzz: 292 | if(srv->numfds > 0) goto nextfd; 293 | lastfd = k; 294 | microsleep(srv->sleeptime_us); 295 | } 296 | return 0; 297 | } 298 | -------------------------------------------------------------------------------- /examples/ssh-socks-restart.c: -------------------------------------------------------------------------------- 1 | /* 2 | SSH proxy "daemon" (C) 2011-2016 rofl0r. 3 | licensed under the MIT license. 4 | 5 | starts ssh client with parameters taken from a config file, then 6 | assures the connection is alive by doing cyclic connection checks 7 | using the SOCKS proxy port requested from the SSH server. 8 | if the connection is found dead, the ssh process is killed and 9 | a new connection established. 10 | the SOCKS proxy functionality is required and the server must be 11 | configured to allow it. 12 | additionally we require key-based authentication without user 13 | interaction (i.e. ssh keys without password). 14 | 15 | the config file has the following form: 16 | 17 | [default] 18 | # parameters that apply to all configurations 19 | SOCKSIF=127.0.0.1:8080 20 | 21 | [server1] 22 | KEY=/path/to/my_rsa_key 23 | LOGIN=user@server1.mynet.com 24 | 25 | [server2] 26 | KEY=/path/to/my_ed25519_key 27 | LOGIN=joe@server2.mynet.com 28 | PORT=222 29 | EXTRA=-R 0.0.0.0:2222:127.0.0.1:22 -q -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null 30 | 31 | "EXTRA" is a field that allows you to specify additional 32 | stuff to append to the ssh commandline. 33 | 34 | (The example above creates a reverse tunnel to localhost's ssh port 35 | and binds it on the remote server on port 2222. 36 | Additionally it enables quiet mode and turns off known_hosts questions 37 | and checks. this is critical if this runs on a remote host you have 38 | no physical access to and rely on this program to work and not ask 39 | questions if something in your setup changed.) 40 | 41 | the program is started with the name of the config file and a 42 | configuration item, 43 | i.e. ./ssh-socks-restart my.conf server1 44 | 45 | [testhosts] 46 | google.com:443 47 | 4.68.80.110:80 48 | msn.com 49 | 15.48.80.55 50 | cnn.com 51 | 18.9.49.46:80 52 | 38.100.128.10:80 53 | 54 | testhosts section contains a list of host:port tuples to connect to 55 | to check if the socks connection is still up. i put some raw ips there 56 | as well to mitigate problems with DNS. 57 | 58 | */ 59 | #include "../rocksock.h" 60 | #include 61 | #include 62 | #include 63 | #include 64 | #include 65 | #include 66 | 67 | static int cfg_gotosection(FILE *f, const char* section, char *buf, size_t bufsize) { 68 | size_t s = strlen(section); 69 | while(fgets(buf, bufsize, f)) { 70 | if(buf[0] == '[' && bufsize > s+2 && buf[1+s] == ']' && !strncmp(buf+1,section,s)) 71 | return 1; 72 | } 73 | return 0; 74 | } 75 | 76 | static char* cfg_getstr(FILE *f, const char* section, const char *key, char* buf, size_t bufsize) { 77 | fseek(f, 0, SEEK_SET); 78 | if(!cfg_gotosection(f, section, buf, bufsize)) return 0; 79 | size_t l = strlen(key); 80 | while(fgets(buf, bufsize, f)) { 81 | if(!strncmp(buf, key, l) && buf[l] == '=') { 82 | size_t x = l; 83 | while(buf[++x] != '\n'); 84 | buf[x] = 0; 85 | memmove(buf, buf + l + 1, x - l); 86 | return buf; 87 | } else if(buf[0] == '[') break; 88 | } 89 | *buf = 0; 90 | return 0; 91 | } 92 | 93 | /* returns the number of elements in the list, 0 if none found, and 94 | a the *negative* count of the elements read so far if the buf 95 | was too small to read the entire section, or more than 96 | 100 elements would have been there. */ 97 | static int cfg_getsection(FILE *f, const char* section, unsigned list_indices[static 100], char* buf, size_t bufsize) { 98 | fseek(f, 0, SEEK_SET); 99 | if(!cfg_gotosection(f, section, buf, bufsize)) return 0; 100 | char *p = buf; 101 | size_t left = bufsize; 102 | unsigned elems = 0; 103 | while(fgets(p, left, f)) { 104 | char *q = strrchr(p, '\n'); 105 | if(!q) return -elems; 106 | *q = 0; 107 | if(p != q) { 108 | list_indices[elems++]=p-buf; 109 | if(p[0] == '[' && q[-1] == ']') return elems; 110 | if(elems == 100) return -elems; 111 | } 112 | q++; 113 | left -= q - p; 114 | p = q; 115 | } 116 | return elems; 117 | } 118 | 119 | static char *try_cfg_getstr(FILE *f, const char* section, const char *key, char* buf, size_t bufsize) { 120 | char *p; 121 | if((p = cfg_getstr(f, section, key, buf, bufsize))) return p; 122 | else return cfg_getstr(f, "default", key, buf, bufsize); 123 | } 124 | 125 | struct testhosts_info { 126 | char buf[4096]; 127 | unsigned count; 128 | unsigned indices[100]; 129 | }; 130 | static int read_config(const char* fn, char *section, char* key, char* login, char* port, char* socksif, char* extra, struct testhosts_info* testhosts) { 131 | printf("reading config...\n"); 132 | FILE* f; 133 | if(!(f = fopen(fn, "r"))) { 134 | printf("error: config file %s not found\n", fn); 135 | return 0; 136 | } 137 | int err = 0; 138 | if(getenv("SOCKSIF")) strcpy(socksif, getenv("SOCKSIF")); 139 | else if(!try_cfg_getstr(f, section, "SOCKSIF", socksif, 128)) err++; 140 | if(!try_cfg_getstr(f, section, "KEY", key, 128)) err++; 141 | if(!try_cfg_getstr(f, section, "LOGIN", login, 128)) err++; 142 | if(err) { 143 | printf("error: SOCKSIF, KEY or LOGIN line missing in config\n"); 144 | fclose(f); 145 | return 0; 146 | } 147 | if(!try_cfg_getstr(f, section, "PORT", port, 128)) strcpy(port, "22"); 148 | try_cfg_getstr(f, section, "EXTRA", extra, 1024); 149 | testhosts->count = abs(cfg_getsection(f, "testhosts", testhosts->indices, testhosts->buf, sizeof testhosts->buf)); 150 | 151 | fclose(f); 152 | return 1; 153 | } 154 | 155 | static char** build_argv(char* key, char* login, char* port, char* socksif, char* extra) { 156 | size_t e_items = 0, el = 0; 157 | char *p = extra; 158 | if(*p) e_items++; 159 | while(*p) { 160 | if(*p == ' ') e_items++; 161 | p++; 162 | el++; 163 | } 164 | size_t asz = (1+1+2+2+2+1+e_items+1)*sizeof(char*); 165 | char **res = malloc(asz+el+1); 166 | if(!res) return 0; 167 | char *ecopy = ((char*)(void*)res)+asz; 168 | memcpy(ecopy, extra, el+1); 169 | char **ret = res; 170 | *(res++)="ssh"; 171 | *(res++)=login; 172 | *(res++)="-i"; 173 | *(res++)=key; 174 | *(res++)="-p"; 175 | *(res++)=port; 176 | *(res++)="-D"; 177 | *(res++)=socksif; 178 | *(res++)="-N"; 179 | p = ecopy; 180 | char *s = ecopy; 181 | while(*p) { 182 | if(*p == ' ') { 183 | *p = 0; 184 | *(res++)=s; 185 | s=p+1; 186 | } 187 | p++; 188 | } 189 | if(s < p) *(res++)=s; 190 | *res=0; 191 | return ret; 192 | } 193 | 194 | static int syntax(char* argv0) { 195 | printf("usage: %s configfile sectionname\n" 196 | "establishes ssh connection with connectivity supervision.\n" 197 | "read comment in source code for more info.\n", argv0); 198 | return 1; 199 | } 200 | 201 | #define PROCWAIT_SEC 10 202 | #define TIMEOUT_SEC 20 203 | 204 | static pid_t child = 0; 205 | 206 | void sighandler(int sig) { 207 | if(child) { 208 | int foo; 209 | kill(child, sig); 210 | waitpid(child, &foo, 0); 211 | } 212 | _exit(1); 213 | } 214 | 215 | int main(int argc, char**argv) { 216 | if(argc != 3) return syntax(argv[0]); 217 | int fails = 0; 218 | signal(SIGTERM, sighandler); 219 | signal(SIGINT, sighandler); 220 | while(1) { 221 | char key[128], login[128], port[128], socksif[128], extra[1024]; 222 | struct testhosts_info testhosts; 223 | if(!read_config(argv[1], argv[2], key, login, port, socksif, extra, &testhosts)) { 224 | dprintf(2, "error processing config\n"); 225 | return 1; 226 | } 227 | dprintf(2, "starting process..."); 228 | if(!(child = fork())) { 229 | char**nargs=build_argv(key, login, port, socksif, extra); 230 | if(!nargs) { 231 | dprintf(2, "out of memory, retrying later...\n"); 232 | e_cont: 233 | sleep(PROCWAIT_SEC); 234 | continue; 235 | } 236 | if(execvp("ssh", nargs)) { 237 | perror("exec"); 238 | free(nargs); 239 | goto e_cont; 240 | } 241 | } 242 | dprintf(2, "%d\n", (int) child); 243 | sleep(PROCWAIT_SEC); 244 | 245 | int connected = 0; 246 | while(1) { 247 | int ret, loc; 248 | ret = waitpid(child, &loc, WNOHANG); 249 | dprintf(2, "got waitpid result %d, stat %d\n", ret, loc); 250 | if(ret == child) { 251 | dprintf(2, "child == ret, break\n"); 252 | break; 253 | } 254 | sleep(connected ? PROCWAIT_SEC : 2); 255 | rocksock rs, *r = &rs; 256 | rs_proxy proxies[1]; 257 | rocksock_init(r, proxies); 258 | //rocksock_set_timeout(r, (TIMEOUT_SEC / (fails+1)) * 1000); 259 | rocksock_set_timeout(r, (TIMEOUT_SEC / 1) * 1000); 260 | char socksbuf[128]; 261 | strcpy(socksbuf, socksif); 262 | char *p = strchr(socksbuf, ':'); 263 | *p = 0; 264 | rocksock_add_proxy(r, RS_PT_SOCKS5, socksbuf, atoi(p+1), 0, 0); 265 | static unsigned srvno = 0; 266 | if(srvno >= testhosts.count) { 267 | if(!srvno) { 268 | dprintf(2, "error: testhosts section missing or no testhosts specified\n"); 269 | return 1; 270 | } 271 | srvno = 0; 272 | } 273 | 274 | char hostnamebuf[524], *port; 275 | snprintf(hostnamebuf, sizeof hostnamebuf, "%s", testhosts.buf+testhosts.indices[srvno++]); 276 | port = strchr(hostnamebuf, ':'); 277 | if(!port) port = "80"; 278 | else *(port++) = 0; 279 | dprintf(2, "connecting to %s...\n", hostnamebuf); 280 | ret = rocksock_connect(r, hostnamebuf, atoi(port), 0); 281 | rocksock_disconnect(r); 282 | rocksock_clear(r); 283 | if(ret) { 284 | fails++; 285 | dprintf(2, "fail %d\n", fails); 286 | if(!connected || fails > 3) { 287 | dprintf(2, "connection failed, killing %d\n", (int) child); 288 | kill(child, SIGKILL); 289 | ret = waitpid(child, &loc, 0); 290 | child = 0; 291 | fails = 0; 292 | break; 293 | } 294 | } else { 295 | dprintf(2, "success.\n"); 296 | fails = 0; 297 | connected = 1; 298 | } 299 | sleep(TIMEOUT_SEC / (fails+1)); 300 | } 301 | sleep(1); 302 | } 303 | } 304 | 305 | -------------------------------------------------------------------------------- /rocksock.c: -------------------------------------------------------------------------------- 1 | /* 2 | * author: rofl0r (C) 2011-2017 3 | * License: LGPL 2.1+ with static linking exception 4 | */ 5 | 6 | /* 7 | * recognized defines: USE_SSL, ROCKSOCK_FILENAME, NO_DNS_SUPPORT 8 | */ 9 | 10 | #undef _POSIX_C_SOURCE 11 | #define _POSIX_C_SOURCE 200809L 12 | #undef _GNU_SOURCE 13 | #define _GNU_SOURCE 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #ifndef SOCK_CLOEXEC 25 | #warning compiling without SOCK_CLOEXEC support 26 | #define SOCK_CLOEXEC 0 27 | #endif 28 | 29 | #include "rocksock.h" 30 | #include "rocksock_internal.h" 31 | #ifdef USE_LIBULZ_SYS 32 | /* use this if you have installed libulz systemwide via make install */ 33 | #include 34 | #include 35 | #elif defined(USE_LIBULZ) 36 | /* use this if you want to use the extracted libulz sources via RcB2. 37 | pass a -I flag pointing to its include dir, like so: -I ../lib/include 38 | to RcB2 */ 39 | #include 40 | #include 41 | #else 42 | /* this version of ipv4fromstring was taken from libulz and tuned to be 43 | more pedantic than the libulz version, so it can be used for isnumericipv4() 44 | as well, as it strictly checks the input for correctness. */ 45 | static int ipv4fromstring(const char* ipstring, unsigned char* fourbytesptr) { 46 | const char* start = ipstring; 47 | size_t outbyte = 0; 48 | while(outbyte < 4) { 49 | if(*ipstring == '.' || !*ipstring) { 50 | fourbytesptr[outbyte] = 0; 51 | size_t b = 0; 52 | unsigned tmp; 53 | switch(ipstring - start) { 54 | case 3: 55 | tmp = (start[b++]-'0')*100; 56 | if(tmp > 200) return 0; 57 | fourbytesptr[outbyte] += tmp; 58 | case 2: 59 | fourbytesptr[outbyte] += (start[b++]-'0')*10; 60 | case 1: 61 | fourbytesptr[outbyte] += (start[b++]-'0'); 62 | break; 63 | default: 64 | return 0; 65 | } 66 | start = ipstring + 1; 67 | outbyte++; 68 | } else { 69 | if(*ipstring < '0' || *ipstring > '9') return 0; 70 | } 71 | if(!*ipstring && outbyte < 4) return 0; 72 | ipstring++; 73 | } 74 | if(ipstring[-1]) return 0; 75 | return 1; 76 | } 77 | 78 | static int isnumericipv4(const char* ipstring) { 79 | unsigned char ip[4]; 80 | return ipv4fromstring(ipstring, ip); 81 | } 82 | #endif 83 | 84 | #ifndef ROCKSOCK_FILENAME 85 | #define ROCKSOCK_FILENAME __FILE__ 86 | #endif 87 | 88 | #ifndef MSG_NOSIGNAL 89 | #define MSG_NOSIGNAL 0 90 | #endif 91 | 92 | #ifdef USE_SSL 93 | #include "rocksock_ssl_internal.h" 94 | #endif 95 | 96 | int rocksock_seterror(rocksock* sock, rs_errorType errortype, int error, const char* file, int line) { 97 | if (!sock) return RS_E_NULL; 98 | sock->lasterror.errortype = errortype; 99 | sock->lasterror.error = error; 100 | sock->lasterror.line = line; 101 | sock->lasterror.file = file; 102 | sock->lasterror.failedProxy = -1; 103 | return error; 104 | } 105 | 106 | #define MKOERR(S, X) rocksock_seterror(S, RS_ET_OWN, X, ROCKSOCK_FILENAME, __LINE__) 107 | #define NOERR(S) rocksock_seterror(S, RS_ET_OWN, 0, NULL, 0) 108 | #define MKSYSERR(S, X) rocksock_seterror(S, RS_ET_SYS, X, ROCKSOCK_FILENAME, __LINE__) 109 | 110 | //#define NO_DNS_SUPPORT 111 | static int rocksock_resolve_host(rocksock* sock, rs_hostInfo* hostinfo, rs_resolveStorage* result) { 112 | if (!sock) return RS_E_NULL; 113 | if (!hostinfo || !hostinfo->host[0] || !hostinfo->port) return MKOERR(sock, RS_E_NULL); 114 | 115 | result->hostaddr = &(result->hostaddr_buf); 116 | 117 | #ifndef NO_DNS_SUPPORT 118 | struct addrinfo hints = {.ai_family = AF_UNSPEC, .ai_socktype = SOCK_STREAM, .ai_flags = AI_ADDRCONFIG}; 119 | int ret; 120 | struct addrinfo *best, *save; 121 | ret = getaddrinfo(hostinfo->host, NULL, &hints, &save); 122 | if(!ret) { 123 | best = save; 124 | while(best->ai_addr->sa_family == AF_INET6 && best->ai_next) best = best->ai_next; 125 | *result->hostaddr = *best; 126 | result->hostaddr->ai_addr = (struct sockaddr*) &(result->hostaddr_aiaddr_buf); 127 | result->hostaddr->ai_next = 0; 128 | *result->hostaddr->ai_addr = *best->ai_addr; 129 | 130 | if(result->hostaddr->ai_addr->sa_family == AF_INET) 131 | ((struct sockaddr_in*) result->hostaddr->ai_addr)->sin_port = htons(hostinfo->port); 132 | else 133 | ((struct sockaddr_in6*) result->hostaddr->ai_addr)->sin6_port = htons(hostinfo->port); 134 | freeaddrinfo(save); 135 | return 0; 136 | } else 137 | return rocksock_seterror(sock, RS_ET_GAI, ret, ROCKSOCK_FILENAME, __LINE__); 138 | #else 139 | result->hostaddr->ai_addr = (struct sockaddr*) &(result->hostaddr_aiaddr_buf); 140 | 141 | ((struct sockaddr_in*) result->hostaddr->ai_addr)->sin_port = htons(hostinfo->port); 142 | ((struct sockaddr_in*) result->hostaddr->ai_addr)->sin_family = AF_INET; 143 | result->hostaddr->ai_addr->sa_family = AF_INET; 144 | result->hostaddr->ai_addrlen = sizeof(struct sockaddr_in); 145 | ipv4fromstring(hostinfo->host, (unsigned char*) &((struct sockaddr_in*) result->hostaddr->ai_addr)->sin_addr); 146 | 147 | return 0; 148 | #endif 149 | } 150 | 151 | int rocksock_set_timeout(rocksock* sock, unsigned long timeout_millisec) { 152 | if (!sock) return RS_E_NULL; 153 | sock->timeout = timeout_millisec; 154 | return NOERR(sock); 155 | } 156 | 157 | int rocksock_init(rocksock* sock, rs_proxy *proxies) { 158 | if (!sock) return RS_E_NULL; 159 | memset(sock, 0, sizeof(rocksock)); 160 | sock->lastproxy = -1; 161 | sock->timeout = 60*1000; 162 | sock->socket = -1; 163 | sock->proxies = proxies; 164 | return NOERR(sock); 165 | } 166 | 167 | static struct timeval* make_timeval(struct timeval* tv, unsigned long timeout) { 168 | if(!tv) return NULL; 169 | tv->tv_sec = timeout / 1000; 170 | tv->tv_usec = 1000 * (timeout % 1000); 171 | return tv; 172 | } 173 | 174 | static int do_connect(rocksock* sock, rs_resolveStorage* hostinfo, unsigned long timeout) { 175 | int flags, ret; 176 | fd_set wset; 177 | struct timeval tv; 178 | int optval; 179 | socklen_t optlen = sizeof(optval); 180 | 181 | sock->socket = socket(hostinfo->hostaddr->ai_family, SOCK_STREAM | SOCK_CLOEXEC, 0); 182 | if(sock->socket == -1) return MKSYSERR(sock, errno); 183 | 184 | /* the socket has to be made non-blocking temporarily so we can enforce a connect timeout */ 185 | flags = fcntl(sock->socket, F_GETFL); 186 | if(flags == -1) return MKSYSERR(sock, errno); 187 | 188 | if(fcntl(sock->socket, F_SETFL, flags | O_NONBLOCK) == -1) return MKSYSERR(sock, errno); 189 | 190 | ret = connect(sock->socket, hostinfo->hostaddr->ai_addr, hostinfo->hostaddr->ai_addrlen); 191 | if(ret == -1) { 192 | ret = errno; 193 | if (!(ret == EINPROGRESS || ret == EWOULDBLOCK)) return MKSYSERR(sock, ret); 194 | } 195 | 196 | if(fcntl(sock->socket, F_SETFL, flags) == -1) return MKSYSERR(sock, errno); 197 | 198 | FD_ZERO(&wset); 199 | FD_SET(sock->socket, &wset); 200 | 201 | ret = select(sock->socket+1, NULL, &wset, NULL, timeout ? make_timeval(&tv, timeout) : NULL); 202 | 203 | if(ret == 1 && FD_ISSET(sock->socket, &wset)) { 204 | ret = getsockopt(sock->socket, SOL_SOCKET, SO_ERROR, &optval,&optlen); 205 | if(ret == -1) return MKSYSERR(sock, errno); 206 | else if(optval) return MKSYSERR(sock, optval); 207 | return 0; 208 | } else if(ret == 0) return MKOERR(sock, RS_E_HIT_CONNECTTIMEOUT); 209 | 210 | return MKSYSERR(sock, errno); 211 | } 212 | 213 | static int rocksock_setup_socks4_header(rocksock* sock, int is4a, char* buffer, rs_proxy* proxy, size_t* bytesused) { 214 | int ret; 215 | buffer[0] = 4; 216 | buffer[1] = 1; 217 | buffer[2] = proxy->hostinfo.port / 256; 218 | buffer[3] = proxy->hostinfo.port % 256; 219 | 220 | if(is4a) { 221 | buffer[4] = 0; 222 | buffer[5] = 0; 223 | buffer[6] = 0; 224 | buffer[7] = 1; 225 | } else { 226 | rs_resolveStorage stor; 227 | ret = rocksock_resolve_host(sock, &proxy->hostinfo, &stor); 228 | if(ret) return ret; 229 | if(stor.hostaddr->ai_family != AF_INET) 230 | return MKOERR(sock, RS_E_SOCKS4_NO_IP6); 231 | buffer[4] = ((char*) &(((struct sockaddr_in*) stor.hostaddr->ai_addr)->sin_addr.s_addr))[0]; 232 | buffer[5] = ((char*) &(((struct sockaddr_in*) stor.hostaddr->ai_addr)->sin_addr.s_addr))[1]; 233 | buffer[6] = ((char*) &(((struct sockaddr_in*) stor.hostaddr->ai_addr)->sin_addr.s_addr))[2]; 234 | buffer[7] = ((char*) &(((struct sockaddr_in*) stor.hostaddr->ai_addr)->sin_addr.s_addr))[3]; 235 | } 236 | buffer[8] = 0; 237 | *bytesused = 9; 238 | if(is4a) { 239 | char *p = buffer + *bytesused; 240 | size_t l = strlen(proxy->hostinfo.host) + 1; 241 | /* memcpy is safe because all functions accepting a hostname check it's < 255 */ 242 | memcpy(p, proxy->hostinfo.host, l); 243 | *bytesused += l; 244 | } 245 | return NOERR(sock); 246 | } 247 | 248 | int rocksock_connect(rocksock* sock, const char* host, unsigned short port, int useSSL) { 249 | ptrdiff_t px; 250 | int ret, trysocksv4a; 251 | rs_hostInfo targethost; 252 | rs_hostInfo* connector; 253 | rs_proxy dummy; 254 | rs_proxy* targetproxy; 255 | char socksdata[768]; 256 | char* p; 257 | size_t socksused = 0, bytes; 258 | if (!sock) return RS_E_NULL; 259 | if (!host || !port) 260 | return MKOERR(sock, RS_E_NULL); 261 | size_t hl = strlen(host); 262 | if(hl > 255) 263 | return MKOERR(sock, RS_E_HOSTNAME_TOO_LONG); 264 | #ifndef USE_SSL 265 | if (useSSL) return MKOERR(sock, RS_E_NO_SSL); 266 | #endif 267 | memcpy(targethost.host, host, hl+1); 268 | targethost.port = port; 269 | 270 | if(sock->lastproxy >= 0) 271 | connector = &sock->proxies[0].hostinfo; 272 | else 273 | connector = &targethost; 274 | 275 | rs_resolveStorage stor; 276 | 277 | ret = rocksock_resolve_host(sock, connector, &stor); 278 | if(ret) { 279 | check_proxy0_failure: 280 | px = -1; 281 | goto proxyfailure; 282 | } 283 | 284 | ret = do_connect(sock, &stor, sock->timeout); 285 | if(ret) goto check_proxy0_failure; 286 | 287 | for(px = 0; px <= sock->lastproxy; px++) { 288 | if(px == sock->lastproxy) { 289 | targetproxy = &dummy; 290 | dummy.hostinfo = targethost; 291 | dummy.password[0] = 0; 292 | dummy.username[0] = 0; 293 | dummy.proxytype = RS_PT_NONE; 294 | } else { 295 | targetproxy = &sock->proxies[px + 1]; 296 | } 297 | // send socks connection data 298 | switch(sock->proxies[px].proxytype) { 299 | case RS_PT_SOCKS4: 300 | trysocksv4a = 1; 301 | trysocks4: 302 | ret = rocksock_setup_socks4_header(sock, trysocksv4a, socksdata, targetproxy, &socksused); 303 | if(ret) { 304 | proxyfailure: 305 | sock->lasterror.failedProxy = px == sock->lastproxy ? -1 : px + 1; 306 | if(sock->socket != -1) { 307 | close(sock->socket); 308 | sock->socket = -1; 309 | } 310 | return ret; 311 | } 312 | ret = rocksock_send(sock, socksdata, socksused, 0, &bytes); 313 | if(ret) goto proxyfailure; 314 | ret = rocksock_recv(sock, socksdata, 8, 8, &bytes); 315 | if(ret) goto proxyfailure; 316 | if(bytes < 8 || socksdata[0] != 0) { 317 | err_unexpected: 318 | ret = MKOERR(sock, RS_E_PROXY_UNEXPECTED_RESPONSE); 319 | goto proxyfailure; 320 | } 321 | switch(socksdata[1]) { 322 | case 0x5a: 323 | break; 324 | case 0x5b: 325 | if(trysocksv4a) { 326 | trysocksv4a = 0; 327 | goto trysocks4; 328 | } 329 | err_proxyconnect: 330 | ret = MKOERR(sock, RS_E_TARGETPROXY_CONNECT_FAILED); 331 | goto proxyfailure; 332 | case 0x5c: case 0x5d: 333 | err_proxyauth: 334 | ret = MKOERR(sock, RS_E_PROXY_AUTH_FAILED); 335 | goto proxyfailure; 336 | default: 337 | goto err_unexpected; 338 | } 339 | break; 340 | case RS_PT_SOCKS5: 341 | p = socksdata; 342 | *p++ = 5; 343 | if(sock->proxies[px].username[0] && sock->proxies[px].password[0]) { 344 | *p++ = 2; 345 | *p++ = 0; 346 | *p++ = 2; 347 | } else { 348 | *p++ = 1; 349 | *p++ = 0; 350 | } 351 | bytes = p - socksdata; 352 | ret = rocksock_send(sock, socksdata, bytes, bytes, &bytes); 353 | if(ret) goto proxyfailure; 354 | ret = rocksock_recv(sock, socksdata, 2, 2, &bytes); 355 | if(ret) goto proxyfailure; 356 | if(bytes < 2 || socksdata[0] != 5) goto err_unexpected; 357 | if(socksdata[1] == '\xff') { 358 | goto err_proxyauth; 359 | } else if (socksdata[1] == 2) { 360 | if(sock->proxies[px].username[0] && sock->proxies[px].password[0]) { 361 | /* 362 | +----+------+----------+------+----------+ 363 | |VER | ULEN | UNAME | PLEN | PASSWD | 364 | +----+------+----------+------+----------+ 365 | | 1 | 1 | 1 to 255 | 1 | 1 to 255 | 366 | +----+------+----------+------+----------+ 367 | */ 368 | p = socksdata; 369 | *p++ = 1; 370 | bytes = strlen(sock->proxies[px].username); 371 | *p++ = bytes; 372 | memcpy(p, sock->proxies[px].username, bytes); 373 | p += bytes; 374 | bytes = strlen(sock->proxies[px].password); 375 | *p++ = bytes; 376 | memcpy(p, sock->proxies[px].password, bytes); 377 | p += bytes; 378 | bytes = p - socksdata; 379 | ret = rocksock_send(sock, socksdata, bytes, bytes, &bytes); 380 | if(ret) goto proxyfailure; 381 | ret = rocksock_recv(sock, socksdata, 2, 2, &bytes); 382 | if(ret) goto proxyfailure; 383 | if(bytes < 2) goto err_unexpected; 384 | else if(socksdata[1] != 0) goto err_proxyauth; 385 | } else { 386 | goto err_proxyauth; 387 | } 388 | } 389 | p = socksdata; 390 | *p++ = 5; 391 | *p++ = 1; 392 | *p++ = 0; 393 | if(isnumericipv4(targetproxy->hostinfo.host)) { 394 | *p++ = 1; // ipv4 method 395 | bytes = 4; 396 | ipv4fromstring(targetproxy->hostinfo.host, (unsigned char*) p); 397 | } else { 398 | *p++ = 3; //hostname method, requires the server to do dns lookups. 399 | bytes = strlen(targetproxy->hostinfo.host); 400 | if(bytes > 255) 401 | return MKOERR(sock, RS_E_SOCKS5_AUTH_EXCEEDSIZE); 402 | *p++ = bytes; 403 | memcpy(p, targetproxy->hostinfo.host, bytes); 404 | } 405 | p+=bytes; 406 | *p++ = targetproxy->hostinfo.port / 256; 407 | *p++ = targetproxy->hostinfo.port % 256; 408 | bytes = p - socksdata; 409 | ret = rocksock_send(sock, socksdata, bytes, bytes, &bytes); 410 | if(ret) goto proxyfailure; 411 | ret = rocksock_recv(sock, socksdata, sizeof(socksdata), sizeof(socksdata), &bytes); 412 | if(ret) goto proxyfailure; 413 | if(bytes < 2) goto err_unexpected; 414 | switch(socksdata[1]) { 415 | case 0: 416 | break; 417 | case 1: 418 | ret = MKOERR(sock, RS_E_PROXY_GENERAL_FAILURE); 419 | goto proxyfailure; 420 | case 2: 421 | goto err_proxyauth; 422 | case 3: 423 | ret = MKOERR(sock, RS_E_TARGETPROXY_NET_UNREACHABLE); 424 | goto proxyfailure; 425 | case 4: 426 | ret = MKOERR(sock, RS_E_TARGETPROXY_HOST_UNREACHABLE); 427 | goto proxyfailure; 428 | case 5: 429 | ret = MKOERR(sock, RS_E_TARGETPROXY_CONN_REFUSED); 430 | goto proxyfailure; 431 | case 6: 432 | ret = MKOERR(sock, RS_E_TARGETPROXY_TTL_EXPIRED); 433 | goto proxyfailure; 434 | case 7: 435 | ret = MKOERR(sock, RS_E_PROXY_COMMAND_NOT_SUPPORTED); 436 | goto proxyfailure; 437 | case 8: 438 | ret = MKOERR(sock, RS_E_PROXY_ADDRESSTYPE_NOT_SUPPORTED); 439 | goto proxyfailure; 440 | default: 441 | goto err_unexpected; 442 | } 443 | break; 444 | case RS_PT_HTTP: 445 | bytes = snprintf(socksdata, sizeof(socksdata), "CONNECT %s:%d HTTP/1.1\r\n\r\n", targetproxy->hostinfo.host, targetproxy->hostinfo.port); 446 | ret = rocksock_send(sock, socksdata, bytes, bytes, &bytes); 447 | if(ret) goto proxyfailure; 448 | ret = rocksock_recv(sock, socksdata, sizeof(socksdata), sizeof(socksdata), &bytes); 449 | if(ret) goto proxyfailure; 450 | if(bytes < 12) goto err_unexpected; 451 | if(socksdata[9] != '2') goto err_proxyconnect; 452 | break; 453 | default: 454 | break; 455 | } 456 | } 457 | 458 | #ifdef USE_SSL 459 | if(useSSL) { 460 | ret = rocksock_ssl_connect_fd(sock); 461 | if(ret) return ret; 462 | } 463 | #endif 464 | return NOERR(sock); 465 | } 466 | 467 | typedef enum { 468 | RS_OT_SEND = 0, 469 | RS_OT_READ 470 | } rs_operationType; 471 | 472 | static int rocksock_operation(rocksock* sock, rs_operationType operation, char* buffer, size_t bufsize, size_t chunksize, size_t* bytes) { 473 | if (!sock) return RS_E_NULL; 474 | if (!buffer || !bytes || (!bufsize && operation == RS_OT_READ)) return MKOERR(sock, RS_E_NULL); 475 | *bytes = 0; 476 | struct timeval tv; 477 | fd_set fd; 478 | fd_set* rfd = NULL; 479 | fd_set* wfd = NULL; 480 | int ret = 0; 481 | size_t bytesleft = bufsize ? bufsize : strlen(buffer); 482 | size_t byteswanted; 483 | char* bufptr = buffer; 484 | 485 | if (sock->socket == -1) return MKOERR(sock, RS_E_NO_SOCKET); 486 | if(operation == RS_OT_SEND) wfd = &fd; 487 | else rfd = &fd; 488 | 489 | if(sock->timeout) { 490 | if(operation == RS_OT_SEND) 491 | ret = setsockopt(sock->socket, SOL_SOCKET, SO_SNDTIMEO, (void*) make_timeval(&tv, sock->timeout), sizeof(tv)); 492 | else 493 | ret = setsockopt(sock->socket, SOL_SOCKET, SO_RCVTIMEO, (void*) make_timeval(&tv, sock->timeout), sizeof(tv)); 494 | } 495 | 496 | if (ret == -1) return MKSYSERR(sock, errno); 497 | 498 | while(bytesleft) { 499 | byteswanted = (chunksize && chunksize < bytesleft) ? chunksize : bytesleft; 500 | #ifdef USE_SSL 501 | if (sock->ssl) { 502 | if(operation == RS_OT_SEND) 503 | ret = rocksock_ssl_send(sock, bufptr, byteswanted); 504 | else 505 | ret = rocksock_ssl_recv(sock, bufptr, byteswanted); 506 | } else { 507 | #endif 508 | /* enforce the timeout by using select() before doing the actual recv/send */ 509 | FD_SET(sock->socket, &fd); 510 | ret=select(sock->socket+1, rfd, wfd, NULL, sock->timeout ? make_timeval(&tv, sock->timeout) : NULL); 511 | if(!FD_ISSET(sock->socket, &fd)) MKOERR(sock, RS_E_NULL); // temp test 512 | if(ret == -1) { 513 | //printf("h: %s, skt: %d, to: %d:%d\n", targethost.host, sock->socket, tv.tv_sec, tv.tv_usec); 514 | return MKSYSERR(sock, errno); 515 | } 516 | else if(!ret) return MKOERR(sock, RS_OT_READ ? RS_E_HIT_READTIMEOUT : RS_E_HIT_WRITETIMEOUT); 517 | 518 | if(operation == RS_OT_SEND) 519 | ret = send(sock->socket, bufptr, byteswanted, MSG_NOSIGNAL); 520 | else 521 | ret = recv(sock->socket, bufptr, byteswanted, 0); 522 | 523 | #ifdef USE_SSL 524 | } 525 | #endif 526 | 527 | if(!ret) // The return value will be 0 when the peer has performed an orderly shutdown. 528 | return MKOERR(sock, RS_E_REMOTE_DISCONNECTED); 529 | else if(ret == -1) { 530 | ret = errno; 531 | if(ret == EWOULDBLOCK || ret == EINPROGRESS) return MKOERR(sock, RS_OT_READ ? RS_E_HIT_READTIMEOUT : RS_E_HIT_WRITETIMEOUT); 532 | return MKSYSERR(sock, errno); 533 | } 534 | 535 | bytesleft -= ret; 536 | bufptr += ret; 537 | *bytes += ret; 538 | if(operation == RS_OT_READ && (size_t) ret < byteswanted) break; 539 | } 540 | return NOERR(sock); 541 | } 542 | 543 | int rocksock_send(rocksock* sock, char* buffer, size_t bufsize, size_t chunksize, size_t* byteswritten) { 544 | return rocksock_operation(sock, RS_OT_SEND, buffer, bufsize, chunksize, byteswritten); 545 | } 546 | 547 | int rocksock_recv(rocksock* sock, char* buffer, size_t bufsize, size_t chunksize, size_t* bytesread) { 548 | return rocksock_operation(sock, RS_OT_READ, buffer, bufsize, chunksize, bytesread); 549 | } 550 | 551 | int rocksock_disconnect(rocksock* sock) { 552 | if (!sock) return RS_E_NULL; 553 | #ifdef USE_SSL 554 | rocksock_ssl_free_context(sock); 555 | #endif 556 | if(sock->socket != -1) close(sock->socket); 557 | sock->socket = -1; 558 | return NOERR(sock); 559 | } 560 | 561 | int rocksock_clear(rocksock* sock) { 562 | if (!sock) return RS_E_NULL; 563 | sock->lastproxy = -1; 564 | sock->proxies = 0; 565 | return NOERR(sock); 566 | } 567 | 568 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 2.1, February 1999 3 | 4 | Copyright (C) 1991, 1999 Free Software Foundation, Inc. 5 | 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | [This is the first released version of the Lesser GPL. It also counts 10 | as the successor of the GNU Library Public License, version 2, hence 11 | the version number 2.1.] 12 | 13 | Preamble 14 | 15 | The licenses for most software are designed to take away your 16 | freedom to share and change it. By contrast, the GNU General Public 17 | Licenses are intended to guarantee your freedom to share and change 18 | free software--to make sure the software is free for all its users. 19 | 20 | This license, the Lesser General Public License, applies to some 21 | specially designated software packages--typically libraries--of the 22 | Free Software Foundation and other authors who decide to use it. You 23 | can use it too, but we suggest you first think carefully about whether 24 | this license or the ordinary General Public License is the better 25 | strategy to use in any particular case, based on the explanations below. 26 | 27 | When we speak of free software, we are referring to freedom of use, 28 | not price. Our General Public Licenses are designed to make sure that 29 | you have the freedom to distribute copies of free software (and charge 30 | for this service if you wish); that you receive source code or can get 31 | it if you want it; that you can change the software and use pieces of 32 | it in new free programs; and that you are informed that you can do 33 | these things. 34 | 35 | To protect your rights, we need to make restrictions that forbid 36 | distributors to deny you these rights or to ask you to surrender these 37 | rights. These restrictions translate to certain responsibilities for 38 | you if you distribute copies of the library or if you modify it. 39 | 40 | For example, if you distribute copies of the library, whether gratis 41 | or for a fee, you must give the recipients all the rights that we gave 42 | you. You must make sure that they, too, receive or can get the source 43 | code. If you link other code with the library, you must provide 44 | complete object files to the recipients, so that they can relink them 45 | with the library after making changes to the library and recompiling 46 | it. And you must show them these terms so they know their rights. 47 | 48 | We protect your rights with a two-step method: (1) we copyright the 49 | library, and (2) we offer you this license, which gives you legal 50 | permission to copy, distribute and/or modify the library. 51 | 52 | To protect each distributor, we want to make it very clear that 53 | there is no warranty for the free library. Also, if the library is 54 | modified by someone else and passed on, the recipients should know 55 | that what they have is not the original version, so that the original 56 | author's reputation will not be affected by problems that might be 57 | introduced by others. 58 | 59 | Finally, software patents pose a constant threat to the existence of 60 | any free program. We wish to make sure that a company cannot 61 | effectively restrict the users of a free program by obtaining a 62 | restrictive license from a patent holder. Therefore, we insist that 63 | any patent license obtained for a version of the library must be 64 | consistent with the full freedom of use specified in this license. 65 | 66 | Most GNU software, including some libraries, is covered by the 67 | ordinary GNU General Public License. This license, the GNU Lesser 68 | General Public License, applies to certain designated libraries, and 69 | is quite different from the ordinary General Public License. We use 70 | this license for certain libraries in order to permit linking those 71 | libraries into non-free programs. 72 | 73 | When a program is linked with a library, whether statically or using 74 | a shared library, the combination of the two is legally speaking a 75 | combined work, a derivative of the original library. The ordinary 76 | General Public License therefore permits such linking only if the 77 | entire combination fits its criteria of freedom. The Lesser General 78 | Public License permits more lax criteria for linking other code with 79 | the library. 80 | 81 | We call this license the "Lesser" General Public License because it 82 | does Less to protect the user's freedom than the ordinary General 83 | Public License. It also provides other free software developers Less 84 | of an advantage over competing non-free programs. These disadvantages 85 | are the reason we use the ordinary General Public License for many 86 | libraries. However, the Lesser license provides advantages in certain 87 | special circumstances. 88 | 89 | For example, on rare occasions, there may be a special need to 90 | encourage the widest possible use of a certain library, so that it becomes 91 | a de-facto standard. To achieve this, non-free programs must be 92 | allowed to use the library. A more frequent case is that a free 93 | library does the same job as widely used non-free libraries. In this 94 | case, there is little to gain by limiting the free library to free 95 | software only, so we use the Lesser General Public License. 96 | 97 | In other cases, permission to use a particular library in non-free 98 | programs enables a greater number of people to use a large body of 99 | free software. For example, permission to use the GNU C Library in 100 | non-free programs enables many more people to use the whole GNU 101 | operating system, as well as its variant, the GNU/Linux operating 102 | system. 103 | 104 | Although the Lesser General Public License is Less protective of the 105 | users' freedom, it does ensure that the user of a program that is 106 | linked with the Library has the freedom and the wherewithal to run 107 | that program using a modified version of the Library. 108 | 109 | The precise terms and conditions for copying, distribution and 110 | modification follow. Pay close attention to the difference between a 111 | "work based on the library" and a "work that uses the library". The 112 | former contains code derived from the library, whereas the latter must 113 | be combined with the library in order to run. 114 | 115 | GNU LESSER GENERAL PUBLIC LICENSE 116 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 117 | 118 | 0. This License Agreement applies to any software library or other 119 | program which contains a notice placed by the copyright holder or 120 | other authorized party saying it may be distributed under the terms of 121 | this Lesser General Public License (also called "this License"). 122 | Each licensee is addressed as "you". 123 | 124 | A "library" means a collection of software functions and/or data 125 | prepared so as to be conveniently linked with application programs 126 | (which use some of those functions and data) to form executables. 127 | 128 | The "Library", below, refers to any such software library or work 129 | which has been distributed under these terms. A "work based on the 130 | Library" means either the Library or any derivative work under 131 | copyright law: that is to say, a work containing the Library or a 132 | portion of it, either verbatim or with modifications and/or translated 133 | straightforwardly into another language. (Hereinafter, translation is 134 | included without limitation in the term "modification".) 135 | 136 | "Source code" for a work means the preferred form of the work for 137 | making modifications to it. For a library, complete source code means 138 | all the source code for all modules it contains, plus any associated 139 | interface definition files, plus the scripts used to control compilation 140 | and installation of the library. 141 | 142 | Activities other than copying, distribution and modification are not 143 | covered by this License; they are outside its scope. The act of 144 | running a program using the Library is not restricted, and output from 145 | such a program is covered only if its contents constitute a work based 146 | on the Library (independent of the use of the Library in a tool for 147 | writing it). Whether that is true depends on what the Library does 148 | and what the program that uses the Library does. 149 | 150 | 1. You may copy and distribute verbatim copies of the Library's 151 | complete source code as you receive it, in any medium, provided that 152 | you conspicuously and appropriately publish on each copy an 153 | appropriate copyright notice and disclaimer of warranty; keep intact 154 | all the notices that refer to this License and to the absence of any 155 | warranty; and distribute a copy of this License along with the 156 | Library. 157 | 158 | You may charge a fee for the physical act of transferring a copy, 159 | and you may at your option offer warranty protection in exchange for a 160 | fee. 161 | 162 | 2. You may modify your copy or copies of the Library or any portion 163 | of it, thus forming a work based on the Library, and copy and 164 | distribute such modifications or work under the terms of Section 1 165 | above, provided that you also meet all of these conditions: 166 | 167 | a) The modified work must itself be a software library. 168 | 169 | b) You must cause the files modified to carry prominent notices 170 | stating that you changed the files and the date of any change. 171 | 172 | c) You must cause the whole of the work to be licensed at no 173 | charge to all third parties under the terms of this License. 174 | 175 | d) If a facility in the modified Library refers to a function or a 176 | table of data to be supplied by an application program that uses 177 | the facility, other than as an argument passed when the facility 178 | is invoked, then you must make a good faith effort to ensure that, 179 | in the event an application does not supply such function or 180 | table, the facility still operates, and performs whatever part of 181 | its purpose remains meaningful. 182 | 183 | (For example, a function in a library to compute square roots has 184 | a purpose that is entirely well-defined independent of the 185 | application. Therefore, Subsection 2d requires that any 186 | application-supplied function or table used by this function must 187 | be optional: if the application does not supply it, the square 188 | root function must still compute square roots.) 189 | 190 | These requirements apply to the modified work as a whole. If 191 | identifiable sections of that work are not derived from the Library, 192 | and can be reasonably considered independent and separate works in 193 | themselves, then this License, and its terms, do not apply to those 194 | sections when you distribute them as separate works. But when you 195 | distribute the same sections as part of a whole which is a work based 196 | on the Library, the distribution of the whole must be on the terms of 197 | this License, whose permissions for other licensees extend to the 198 | entire whole, and thus to each and every part regardless of who wrote 199 | it. 200 | 201 | Thus, it is not the intent of this section to claim rights or contest 202 | your rights to work written entirely by you; rather, the intent is to 203 | exercise the right to control the distribution of derivative or 204 | collective works based on the Library. 205 | 206 | In addition, mere aggregation of another work not based on the Library 207 | with the Library (or with a work based on the Library) on a volume of 208 | a storage or distribution medium does not bring the other work under 209 | the scope of this License. 210 | 211 | 3. You may opt to apply the terms of the ordinary GNU General Public 212 | License instead of this License to a given copy of the Library. To do 213 | this, you must alter all the notices that refer to this License, so 214 | that they refer to the ordinary GNU General Public License, version 2, 215 | instead of to this License. (If a newer version than version 2 of the 216 | ordinary GNU General Public License has appeared, then you can specify 217 | that version instead if you wish.) Do not make any other change in 218 | these notices. 219 | 220 | Once this change is made in a given copy, it is irreversible for 221 | that copy, so the ordinary GNU General Public License applies to all 222 | subsequent copies and derivative works made from that copy. 223 | 224 | This option is useful when you wish to copy part of the code of 225 | the Library into a program that is not a library. 226 | 227 | 4. You may copy and distribute the Library (or a portion or 228 | derivative of it, under Section 2) in object code or executable form 229 | under the terms of Sections 1 and 2 above provided that you accompany 230 | it with the complete corresponding machine-readable source code, which 231 | must be distributed under the terms of Sections 1 and 2 above on a 232 | medium customarily used for software interchange. 233 | 234 | If distribution of object code is made by offering access to copy 235 | from a designated place, then offering equivalent access to copy the 236 | source code from the same place satisfies the requirement to 237 | distribute the source code, even though third parties are not 238 | compelled to copy the source along with the object code. 239 | 240 | 5. A program that contains no derivative of any portion of the 241 | Library, but is designed to work with the Library by being compiled or 242 | linked with it, is called a "work that uses the Library". Such a 243 | work, in isolation, is not a derivative work of the Library, and 244 | therefore falls outside the scope of this License. 245 | 246 | However, linking a "work that uses the Library" with the Library 247 | creates an executable that is a derivative of the Library (because it 248 | contains portions of the Library), rather than a "work that uses the 249 | library". The executable is therefore covered by this License. 250 | Section 6 states terms for distribution of such executables. 251 | 252 | When a "work that uses the Library" uses material from a header file 253 | that is part of the Library, the object code for the work may be a 254 | derivative work of the Library even though the source code is not. 255 | Whether this is true is especially significant if the work can be 256 | linked without the Library, or if the work is itself a library. The 257 | threshold for this to be true is not precisely defined by law. 258 | 259 | If such an object file uses only numerical parameters, data 260 | structure layouts and accessors, and small macros and small inline 261 | functions (ten lines or less in length), then the use of the object 262 | file is unrestricted, regardless of whether it is legally a derivative 263 | work. (Executables containing this object code plus portions of the 264 | Library will still fall under Section 6.) 265 | 266 | Otherwise, if the work is a derivative of the Library, you may 267 | distribute the object code for the work under the terms of Section 6. 268 | Any executables containing that work also fall under Section 6, 269 | whether or not they are linked directly with the Library itself. 270 | 271 | 6. As an exception to the Sections above, you may also combine or 272 | link a "work that uses the Library" with the Library to produce a 273 | work containing portions of the Library, and distribute that work 274 | under terms of your choice, provided that the terms permit 275 | modification of the work for the customer's own use and reverse 276 | engineering for debugging such modifications. 277 | 278 | You must give prominent notice with each copy of the work that the 279 | Library is used in it and that the Library and its use are covered by 280 | this License. You must supply a copy of this License. If the work 281 | during execution displays copyright notices, you must include the 282 | copyright notice for the Library among them, as well as a reference 283 | directing the user to the copy of this License. Also, you must do one 284 | of these things: 285 | 286 | a) Accompany the work with the complete corresponding 287 | machine-readable source code for the Library including whatever 288 | changes were used in the work (which must be distributed under 289 | Sections 1 and 2 above); and, if the work is an executable linked 290 | with the Library, with the complete machine-readable "work that 291 | uses the Library", as object code and/or source code, so that the 292 | user can modify the Library and then relink to produce a modified 293 | executable containing the modified Library. (It is understood 294 | that the user who changes the contents of definitions files in the 295 | Library will not necessarily be able to recompile the application 296 | to use the modified definitions.) 297 | 298 | b) Use a suitable shared library mechanism for linking with the 299 | Library. A suitable mechanism is one that (1) uses at run time a 300 | copy of the library already present on the user's computer system, 301 | rather than copying library functions into the executable, and (2) 302 | will operate properly with a modified version of the library, if 303 | the user installs one, as long as the modified version is 304 | interface-compatible with the version that the work was made with. 305 | 306 | c) Accompany the work with a written offer, valid for at 307 | least three years, to give the same user the materials 308 | specified in Subsection 6a, above, for a charge no more 309 | than the cost of performing this distribution. 310 | 311 | d) If distribution of the work is made by offering access to copy 312 | from a designated place, offer equivalent access to copy the above 313 | specified materials from the same place. 314 | 315 | e) Verify that the user has already received a copy of these 316 | materials or that you have already sent this user a copy. 317 | 318 | For an executable, the required form of the "work that uses the 319 | Library" must include any data and utility programs needed for 320 | reproducing the executable from it. However, as a special exception, 321 | the materials to be distributed need not include anything that is 322 | normally distributed (in either source or binary form) with the major 323 | components (compiler, kernel, and so on) of the operating system on 324 | which the executable runs, unless that component itself accompanies 325 | the executable. 326 | 327 | It may happen that this requirement contradicts the license 328 | restrictions of other proprietary libraries that do not normally 329 | accompany the operating system. Such a contradiction means you cannot 330 | use both them and the Library together in an executable that you 331 | distribute. 332 | 333 | 7. You may place library facilities that are a work based on the 334 | Library side-by-side in a single library together with other library 335 | facilities not covered by this License, and distribute such a combined 336 | library, provided that the separate distribution of the work based on 337 | the Library and of the other library facilities is otherwise 338 | permitted, and provided that you do these two things: 339 | 340 | a) Accompany the combined library with a copy of the same work 341 | based on the Library, uncombined with any other library 342 | facilities. This must be distributed under the terms of the 343 | Sections above. 344 | 345 | b) Give prominent notice with the combined library of the fact 346 | that part of it is a work based on the Library, and explaining 347 | where to find the accompanying uncombined form of the same work. 348 | 349 | 8. You may not copy, modify, sublicense, link with, or distribute 350 | the Library except as expressly provided under this License. Any 351 | attempt otherwise to copy, modify, sublicense, link with, or 352 | distribute the Library is void, and will automatically terminate your 353 | rights under this License. However, parties who have received copies, 354 | or rights, from you under this License will not have their licenses 355 | terminated so long as such parties remain in full compliance. 356 | 357 | 9. You are not required to accept this License, since you have not 358 | signed it. However, nothing else grants you permission to modify or 359 | distribute the Library or its derivative works. These actions are 360 | prohibited by law if you do not accept this License. Therefore, by 361 | modifying or distributing the Library (or any work based on the 362 | Library), you indicate your acceptance of this License to do so, and 363 | all its terms and conditions for copying, distributing or modifying 364 | the Library or works based on it. 365 | 366 | 10. Each time you redistribute the Library (or any work based on the 367 | Library), the recipient automatically receives a license from the 368 | original licensor to copy, distribute, link with or modify the Library 369 | subject to these terms and conditions. You may not impose any further 370 | restrictions on the recipients' exercise of the rights granted herein. 371 | You are not responsible for enforcing compliance by third parties with 372 | this License. 373 | 374 | 11. If, as a consequence of a court judgment or allegation of patent 375 | infringement or for any other reason (not limited to patent issues), 376 | conditions are imposed on you (whether by court order, agreement or 377 | otherwise) that contradict the conditions of this License, they do not 378 | excuse you from the conditions of this License. If you cannot 379 | distribute so as to satisfy simultaneously your obligations under this 380 | License and any other pertinent obligations, then as a consequence you 381 | may not distribute the Library at all. For example, if a patent 382 | license would not permit royalty-free redistribution of the Library by 383 | all those who receive copies directly or indirectly through you, then 384 | the only way you could satisfy both it and this License would be to 385 | refrain entirely from distribution of the Library. 386 | 387 | If any portion of this section is held invalid or unenforceable under any 388 | particular circumstance, the balance of the section is intended to apply, 389 | and the section as a whole is intended to apply in other circumstances. 390 | 391 | It is not the purpose of this section to induce you to infringe any 392 | patents or other property right claims or to contest validity of any 393 | such claims; this section has the sole purpose of protecting the 394 | integrity of the free software distribution system which is 395 | implemented by public license practices. Many people have made 396 | generous contributions to the wide range of software distributed 397 | through that system in reliance on consistent application of that 398 | system; it is up to the author/donor to decide if he or she is willing 399 | to distribute software through any other system and a licensee cannot 400 | impose that choice. 401 | 402 | This section is intended to make thoroughly clear what is believed to 403 | be a consequence of the rest of this License. 404 | 405 | 12. If the distribution and/or use of the Library is restricted in 406 | certain countries either by patents or by copyrighted interfaces, the 407 | original copyright holder who places the Library under this License may add 408 | an explicit geographical distribution limitation excluding those countries, 409 | so that distribution is permitted only in or among countries not thus 410 | excluded. In such case, this License incorporates the limitation as if 411 | written in the body of this License. 412 | 413 | 13. The Free Software Foundation may publish revised and/or new 414 | versions of the Lesser General Public License from time to time. 415 | Such new versions will be similar in spirit to the present version, 416 | but may differ in detail to address new problems or concerns. 417 | 418 | Each version is given a distinguishing version number. If the Library 419 | specifies a version number of this License which applies to it and 420 | "any later version", you have the option of following the terms and 421 | conditions either of that version or of any later version published by 422 | the Free Software Foundation. If the Library does not specify a 423 | license version number, you may choose any version ever published by 424 | the Free Software Foundation. 425 | 426 | 14. If you wish to incorporate parts of the Library into other free 427 | programs whose distribution conditions are incompatible with these, 428 | write to the author to ask for permission. For software which is 429 | copyrighted by the Free Software Foundation, write to the Free 430 | Software Foundation; we sometimes make exceptions for this. Our 431 | decision will be guided by the two goals of preserving the free status 432 | of all derivatives of our free software and of promoting the sharing 433 | and reuse of software generally. 434 | 435 | NO WARRANTY 436 | 437 | 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO 438 | WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. 439 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR 440 | OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY 441 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE 442 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 443 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 444 | LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME 445 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 446 | 447 | 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN 448 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY 449 | AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU 450 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR 451 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE 452 | LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING 453 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A 454 | FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF 455 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 456 | DAMAGES. 457 | 458 | END OF TERMS AND CONDITIONS 459 | 460 | How to Apply These Terms to Your New Libraries 461 | 462 | If you develop a new library, and you want it to be of the greatest 463 | possible use to the public, we recommend making it free software that 464 | everyone can redistribute and change. You can do so by permitting 465 | redistribution under these terms (or, alternatively, under the terms of the 466 | ordinary General Public License). 467 | 468 | To apply these terms, attach the following notices to the library. It is 469 | safest to attach them to the start of each source file to most effectively 470 | convey the exclusion of warranty; and each file should have at least the 471 | "copyright" line and a pointer to where the full notice is found. 472 | 473 | 474 | Copyright (C) 475 | 476 | This library is free software; you can redistribute it and/or 477 | modify it under the terms of the GNU Lesser General Public 478 | License as published by the Free Software Foundation; either 479 | version 2 of the License, or (at your option) any later version. 480 | 481 | This library is distributed in the hope that it will be useful, 482 | but WITHOUT ANY WARRANTY; without even the implied warranty of 483 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 484 | Lesser General Public License for more details. 485 | 486 | You should have received a copy of the GNU Lesser General Public 487 | License along with this library; if not, write to the Free Software 488 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 489 | 490 | Also add information on how to contact you by electronic and paper mail. 491 | 492 | You should also get your employer (if you work as a programmer) or your 493 | school, if any, to sign a "copyright disclaimer" for the library, if 494 | necessary. Here is a sample; alter the names: 495 | 496 | Yoyodyne, Inc., hereby disclaims all copyright interest in the 497 | library `Frob' (a library for tweaking knobs) written by James Random Hacker. 498 | 499 | , 1 April 1990 500 | Ty Coon, President of Vice 501 | 502 | That's all there is to it! 503 | 504 | 505 | --------------------------------------------------------------------------------