static int ssl_setup(int *rfd, SSL **ssl, SSL_CTX **ctx, struct conf *conf) { BIO *sbio=NULL; char buf[256]=""; ssl_load_globals(); if(!(*ctx=ssl_initialise_ctx(conf))) { logp("error initialising ssl ctx\n"); return -1; } SSL_CTX_set_session_id_context(*ctx, (const unsigned char *)&s_server_session_id_context, sizeof(s_server_session_id_context)); if((*rfd=init_client_socket(conf->server, conf->port))<0) return -1; if(!(*ssl=SSL_new(*ctx)) || !(sbio=BIO_new_socket(*rfd, BIO_NOCLOSE))) { ERR_error_string_n(ERR_get_error(), buf, sizeof(buf)); logp("Problem joining SSL to the socket: %s\n", buf); return -1; } SSL_set_bio(*ssl, sbio, sbio); if(SSL_connect(*ssl)<=0) { ERR_error_string_n(ERR_get_error(), buf, sizeof(buf)); logp("SSL connect error: %s\n", buf); return -1; } return 0; }
static int ssl_setup(int *rfd, SSL **ssl, SSL_CTX **ctx, enum action action, struct conf **confs) { BIO *sbio=NULL; ssl_load_globals(); if(!(*ctx=ssl_initialise_ctx(confs))) { logp("error initialising ssl ctx\n"); return -1; } SSL_CTX_set_session_id_context(*ctx, (const uint8_t *)&s_server_session_id_context, sizeof(s_server_session_id_context)); if((*rfd=init_client_socket(get_string(confs[OPT_SERVER]), action==ACTION_MONITOR? get_string(confs[OPT_STATUS_PORT]):get_string(confs[OPT_PORT])))<0) return -1; if(!(*ssl=SSL_new(*ctx)) || !(sbio=BIO_new_socket(*rfd, BIO_NOCLOSE))) { logp_ssl_err("Problem joining SSL to the socket\n"); return -1; } SSL_set_bio(*ssl, sbio, sbio); if(SSL_connect(*ssl)<=0) { logp_ssl_err("SSL connect error\n"); return -1; } return 0; }
int main (void) { void *socket = init_client_socket(init_context(),ZMQ_PUSH,"tcp://localhost:5555"); FILE *in = stdin; size_t bytes_read; size_t bytes_used; char *line; while(-1 != (bytes_read = getline(&line,&bytes_used,in))) { send(socket, line, bytes_read); } return EXIT_SUCCESS; }
int main(int argc, char ** argv) { ssize_t received, sent, bytes; struct sigaction old_signal_action; /* Input sanitation */ if (argc != 3) { fprintf(stderr, "USAGE: %s listen_port bank_port\n", argv[0]); return EXIT_FAILURE; } /* Capture SIGINT and SIGTERM */ memset(&session_data.signal_action, '\0', sizeof(struct sigaction)); sigfillset(&session_data.signal_action.sa_mask); session_data.signal_action.sa_handler = &handle_signal; sigemptyset(&session_data.termination_signals); sigaction(SIGINT, NULL, &old_signal_action); if (old_signal_action.sa_handler != SIG_IGN) { sigaction(SIGINT, &session_data.signal_action, NULL); sigaddset(&session_data.termination_signals, SIGINT); } sigaction(SIGTERM, NULL, &old_signal_action); if (old_signal_action.sa_handler != SIG_IGN) { sigaction(SIGTERM, &session_data.signal_action, NULL); sigaddset(&session_data.termination_signals, SIGTERM); } /* Socket initialization */ if ((session_data.csock = init_client_socket(argv[2])) < 0) { fprintf(stderr, "ERROR: unable to connect to server\n"); return EXIT_FAILURE; } if ((session_data.ssock = init_server_socket(argv[1])) < 0) { fprintf(stderr, "ERROR: unable to start server\n"); destroy_socket(session_data.csock); return EXIT_FAILURE; } /* Provide a dumb echo tunnel service TODO send/recv threads */ while (!handle_connection(session_data.ssock, &session_data.conn)) { session_data.mode = A2B; session_data.count = 0; while (!handle_relay(&received, &sent)) { /* Report leaky transmissions */ if (sent != received) { bytes = sent - received; if (bytes < 0) { bytes = -bytes; } fprintf(stderr, "ERROR: %li byte(s) lost\n", (long)(bytes)); } /* NOTE: modality is swapped after relay */ if (session_data.mode == A2B) { fprintf(stderr, "INFO: server sent message [id: %08i]\n", session_data.count); } if (session_data.mode == B2A) { fprintf(stderr, "INFO: client sent message [id: %08i]\n", session_data.count); } #ifndef NDEBUG /* Report entire transmission */ hexdump(stderr, session_data.buffer, MAX_COMMAND_LENGTH); #endif } time(&session_data.terminated); fprintf(stderr, "INFO: tunnel closed [%i msg / %li sec]\n", session_data.count, (long)(session_data.terminated - session_data.established)); /* Disconnect from defunct clients */ destroy_socket(session_data.conn); /* Re-establish with the server TODO should this be necessary? */ destroy_socket(session_data.csock); session_data.csock = init_client_socket(argv[2]); } /* Teardown */ handle_signal(0); return EXIT_SUCCESS; }
int status_client_ncurses(struct config *conf, enum action act, const char *sclient) { int fd=0; int ret=0; int sel=0; char *rbuf=NULL; char buf[512]=""; int count=0; int details=0; char *last_rbuf=NULL; int srbr=0; char *client=NULL; int enterpressed=0; // int loop=0; int reqdone=0; #ifdef HAVE_NCURSES_H int stdinfd=fileno(stdin); actg=act; // So that the sighandler can call endwin(). #else if(act==ACTION_STATUS) { printf("To use the live status monitor, you need to recompile with ncurses support.\n"); return -1; } #endif setup_signals(); /* NULL == ::1 or 127.0.0.1 */ if((fd=init_client_socket(NULL, conf->status_port))<0) return -1; set_non_blocking(fd); #ifdef HAVE_NCURSES_H if(actg==ACTION_STATUS) { initscr(); start_color(); init_pair(1, COLOR_WHITE, COLOR_BLACK); init_pair(2, COLOR_WHITE, COLOR_BLACK); init_pair(3, COLOR_WHITE, COLOR_BLACK); raw(); keypad(stdscr, TRUE); noecho(); curs_set(0); halfdelay(3); //nodelay(stdscr, TRUE); } #endif #ifdef DBFP dbfp=fopen("/tmp/dbfp", "w"); #endif while(!ret) { int l; int mfd=-1; fd_set fsr; fd_set fse; struct timeval tval; // Failsafe to prevent the snapshot ever getting permanently // stuck. //if(act==ACTION_STATUS_SNAPSHOT && loop++>10000) // break; if(sclient && !client) { client=strdup(sclient); details=1; } if((enterpressed || need_status()) && !reqdone) { char *req=NULL; if(details && client) req=client; if(request_status(fd, req, conf)) { ret=-1; break; } enterpressed=0; if(act==ACTION_STATUS_SNAPSHOT) reqdone++; } FD_ZERO(&fsr); FD_ZERO(&fse); tval.tv_sec=1; tval.tv_usec=0; add_fd_to_sets(fd, &fsr, NULL, &fse, &mfd); #ifdef HAVE_NCURSES_H if(actg==ACTION_STATUS) add_fd_to_sets(stdinfd, &fsr, NULL, &fse, &mfd); #endif if(select(mfd+1, &fsr, NULL, &fse, &tval)<0) { if(errno!=EAGAIN && errno!=EINTR) { logp("select error: %s\n", strerror(errno)); ret=-1; break; } continue; } if(FD_ISSET(fd, &fse)) { ret=-1; break; } #ifdef HAVE_NCURSES_H if(actg==ACTION_STATUS) { if(FD_ISSET(stdinfd, &fse)) { ret=-1; break; } if(FD_ISSET(stdinfd, &fsr)) { int quit=0; switch(getch()) { case 'q': case 'Q': quit++; break; case KEY_UP: case 'k': case 'K': if(details) break; sel--; break; case KEY_DOWN: case 'j': case 'J': if(details) break; sel++; break; case KEY_ENTER: case '\n': case ' ': if(details) details=0; else details++; enterpressed++; break; case KEY_LEFT: case 'h': case 'H': details=0; break; case KEY_RIGHT: case 'l': case 'L': details++; break; case KEY_NPAGE: { int row=0, col=0; getmaxyx(stdscr, row, col); sel+=row-TOP_SPACE; break; } case KEY_PPAGE: { int row=0, col=0; getmaxyx(stdscr, row, col); sel-=row-TOP_SPACE; break; } } if(quit) break; if(sel<0) sel=0; if(sel>=count) sel=count-1; // Attempt to print stuff to the screen right // now, to give the impression of key strokes // being responsive. if(!details && !sclient) { if((srbr=show_rbuf(last_rbuf, conf, sel, &client, &count, details, sclient))<0) { ret=-1; break; } if(!details) print_star(sel); refresh(); } } } #endif if(FD_ISSET(fd, &fsr)) { // ready to read. if((l=read(fd, buf, sizeof(buf)-1))>0) { size_t r=0; buf[l]='\0'; if(rbuf) r=strlen(rbuf); rbuf=(char *)realloc(rbuf, r+l+1); if(!r) *rbuf='\0'; strcat(rbuf+r, buf); } else break; if(act==ACTION_STATUS_SNAPSHOT) { if(rbuf) { if(!strcmp(rbuf, "\n")) { // This happens when there are // no backup clients. break; } if(strstr(rbuf, "\n-list end-\n")) { printf("%s", rbuf); break; } } continue; } //if(rbuf) printf("rbuf: %s\n", rbuf); /* if(l<0) { ret=-1; break; } */ } if((srbr=show_rbuf(rbuf, conf, sel, &client, &count, details, sclient))<0) { ret=-1; break; } else if(srbr) { // Remember it, so that we can present the detailed // screen without delay, above. if(last_rbuf) free(last_rbuf); last_rbuf=rbuf; rbuf=NULL; } if(sclient) details++; usleep(20000); #ifdef HAVE_NCURSES_H if(actg==ACTION_STATUS) { flushinp(); continue; } #endif if(count) { printf("\n"); break; } } #ifdef HAVE_NCURSES_H if(actg==ACTION_STATUS) endwin(); #endif close_fd(&fd); if(last_rbuf) free(last_rbuf); if(rbuf) free(rbuf); #ifdef DBFP if(dbfp) fclose(dbfp); #endif return ret; }
/* May return 1 to mean try again. This happens after a successful certificate signing request so that it connects again straight away with the new key/certificate. Returns 2 if there were restore/verify warnings. Returns 3 if timer conditions were not met. */ static int do_client(struct config *conf, enum action act, int vss_restore, int json) { int ret=0; int rfd=-1; int resume=0; SSL *ssl=NULL; BIO *sbio=NULL; char buf[256]=""; SSL_CTX *ctx=NULL; struct cntr cntr; struct cntr p1cntr; char *incexc=NULL; char *server_version=NULL; const char *phase1str="backupphase1"; reset_filecounter(&p1cntr, time(NULL)); reset_filecounter(&cntr, time(NULL)); setup_signals_client(); // settimers(0, 100); logp("begin client\n"); if(act!=ACTION_ESTIMATE) { ssl_load_globals(); if(!(ctx=ssl_initialise_ctx(conf))) { logp("error initialising ssl ctx\n"); ret=-1; goto end; } SSL_CTX_set_session_id_context(ctx, (const unsigned char *)&s_server_session_id_context, sizeof(s_server_session_id_context)); if((rfd=init_client_socket(conf->server, conf->port))<0) { ret=-1; goto end; } if(!(ssl=SSL_new(ctx)) || !(sbio=BIO_new_socket(rfd, BIO_NOCLOSE))) { ERR_error_string_n(ERR_get_error(), buf, sizeof(buf)); logp("Problem joining SSL to the socket: %s\n", buf); ret=-1; goto end; } SSL_set_bio(ssl, sbio, sbio); if(SSL_connect(ssl)<=0) { ERR_error_string_n(ERR_get_error(), buf, sizeof(buf)); logp("SSL connect error: %s\n", buf); ret=-1; goto end; } } if((ret=async_init(rfd, ssl, conf, act==ACTION_ESTIMATE))) goto end; // Set quality of service bits on backup packets. if(act==ACTION_BACKUP || act==ACTION_BACKUP_TIMED) set_bulk_packets(); if(act!=ACTION_ESTIMATE) { char cmd=0; size_t len=0; char *feat=NULL; int ca_ret=0; if((ret=authorise_client(conf, &server_version, &p1cntr))) goto end; if(server_version) { logp("Server version: %s\n", server_version); // Servers before 1.3.2 did not tell us their versions. // 1.3.2 and above can do the automatic CA stuff that // follows. if((ca_ret=ca_client_setup(conf, &p1cntr))<0) { // Error logp("Error with certificate signing request\n"); ret=-1; goto end; } else if(ca_ret>0) { // Certificate signed successfully. // Everything is OK, but we will reconnect now, in // order to use the new keys/certificates. ret=1; goto end; } } set_non_blocking(rfd); if((ret=ssl_check_cert(ssl, conf))) { logp("check cert failed\n"); goto end; } if((ret=async_write_str(CMD_GEN, "extra_comms_begin"))) { logp("Problem requesting extra_comms_begin\n"); goto end; } // Servers greater than 1.3.0 will list the extra_comms // features they support. else if((ret=async_read(&cmd, &feat, &len))) { logp("Problem reading response to extra_comms_begin\n"); goto end; } else if(cmd!=CMD_GEN) { logp("Unexpected command from server when reading response to extra_comms_begin: %c:%s\n", cmd, feat); ret=-1; goto end; } else if(strncmp(feat, "extra_comms_begin ok", strlen("extra_comms_begin ok"))) { logp("Unexpected response from server when reading response to extra_comms_begin: %c:%s\n", cmd, feat); ret=-1; goto end; } // Can add extra bits here. The first extra bit is the // autoupgrade stuff. if(server_supports_autoupgrade(feat)) { if(conf->autoupgrade_dir && conf->autoupgrade_os && (ret=autoupgrade_client(conf, &p1cntr))) goto end; } // :srestore: means that the server wants to do a restore. if(server_supports(feat, ":srestore:")) { if(conf->server_can_restore) { logp("Server is initiating a restore\n"); if(incexc) { free(incexc); incexc=NULL; } if((ret=incexc_recv_client_restore(&incexc, conf, &p1cntr))) goto end; if(incexc) { if((ret=parse_incexcs_buf(conf, incexc))) goto end; act=ACTION_RESTORE; log_restore_settings(conf, 1); } } else { logp("Server wants to initiate a restore\n"); logp("Client configuration says no\n"); if(async_write_str(CMD_GEN, "srestore not ok")) { ret=-1; goto end; } } } if(conf->orig_client) { char str[512]=""; snprintf(str, sizeof(str), "orig_client=%s", conf->orig_client); if(!server_supports(feat, ":orig_client:")) { logp("Server does not support switching client.\n"); ret=-1; goto end; } if((ret=async_write_str(CMD_GEN, str)) || (ret=async_read_expect(CMD_GEN, "orig_client ok"))) { logp("Problem requesting %s\n", str); ret=-1; goto end; } logp("Switched to client %s\n", conf->orig_client); } // :sincexc: is for the server giving the client the // incexc config. if(act==ACTION_BACKUP || act==ACTION_BACKUP_TIMED) { if(!incexc && server_supports(feat, ":sincexc:")) { logp("Server is setting includes/excludes.\n"); if(incexc) { free(incexc); incexc=NULL; } if((ret=incexc_recv_client(&incexc, conf, &p1cntr))) goto end; if(incexc && (ret=parse_incexcs_buf(conf, incexc))) goto end; } } if(server_supports(feat, ":counters:")) { if(async_write_str(CMD_GEN, "countersok")) goto end; conf->send_client_counters=1; } // :incexc: is for the client sending the server the // incexc config so that it better knows what to do on // resume. if(server_supports(feat, ":incexc:") && (ret=incexc_send_client(conf, &p1cntr))) goto end; if((ret=async_write_str(CMD_GEN, "extra_comms_end")) || (ret=async_read_expect(CMD_GEN, "extra_comms_end ok"))) { logp("Problem requesting extra_comms_end\n"); goto end; } if(feat) free(feat); } rfd=-1; switch(act) { case ACTION_BACKUP_TIMED: phase1str="backupphase1timed"; case ACTION_BACKUP: { // Set bulk packets quality of service flags on backup. if(incexc) { logp("Server is overriding the configuration\n"); logp("with the following settings:\n"); if(log_incexcs_buf(incexc)) { ret=-1; goto end; } } if(!conf->sdcount) { logp("Found no include paths!\n"); ret=-1; goto end; } if(!(ret=maybe_check_timer(phase1str, conf, &resume))) { if(conf->backup_script_pre) { int a=0; const char *args[12]; args[a++]=conf->backup_script_pre; args[a++]="pre"; args[a++]="reserved2"; args[a++]="reserved3"; args[a++]="reserved4"; args[a++]="reserved5"; args[a++]=NULL; if(run_script(args, conf->backup_script_pre_arg, conf->bprecount, &p1cntr, 1, 1)) ret=-1; } if(!ret && do_backup_client(conf, resume, 0, &p1cntr, &cntr)) ret=-1; if((conf->backup_script_post_run_on_fail || !ret) && conf->backup_script_post) { int a=0; const char *args[12]; args[a++]=conf->backup_script_post; args[a++]="post"; // Tell post script whether the restore // failed. args[a++]=ret?"1":"0"; args[a++]="reserved3"; args[a++]="reserved4"; args[a++]="reserved5"; args[a++]=NULL; if(run_script(args, conf->backup_script_post_arg, conf->bpostcount, &cntr, 1, 1)) ret=-1; } } if(ret<0) logp("error in backup\n"); else if(ret>0) { // Timer script said no. // Have a distinct return value to // differentiate between other cases // (ssl reconnection and restore/verify // warnings). ret=3; } else logp("backup finished ok\n"); break; } case ACTION_RESTORE: case ACTION_VERIFY: { if(conf->restore_script_pre) { int a=0; const char *args[12]; args[a++]=conf->restore_script_pre; args[a++]="pre"; args[a++]="reserved2"; args[a++]="reserved3"; args[a++]="reserved4"; args[a++]="reserved5"; args[a++]=NULL; if(run_script(args, conf->restore_script_pre_arg, conf->rprecount, &cntr, 1, 1)) ret=-1; } if(!ret && do_restore_client(conf, act, vss_restore, &p1cntr, &cntr)) ret=-1; if((conf->restore_script_post_run_on_fail || !ret) && conf->restore_script_post) { int a=0; const char *args[12]; args[a++]=conf->restore_script_pre; args[a++]="post"; // Tell post script whether the restore // failed. args[a++]=ret?"1":"0"; args[a++]="reserved3"; args[a++]="reserved4"; args[a++]="reserved5"; args[a++]=NULL; if(run_script(args, conf->restore_script_post_arg, conf->rpostcount, &cntr, 1, 1)) ret=-1; } // Return non-zero if there were warnings, // so that the test script can easily check. if(p1cntr.warning+cntr.warning) ret=2; break; } case ACTION_ESTIMATE: if(!ret) ret=do_backup_client(conf, 0, 1, &p1cntr, &cntr); break; case ACTION_DELETE: if(!ret) ret=do_delete_client(conf); break; case ACTION_LIST: case ACTION_LONG_LIST: default: ret=do_list_client(conf, act, json); break; } end: close_fd(&rfd); async_free(); if(act!=ACTION_ESTIMATE) ssl_destroy_ctx(ctx); if(incexc) free(incexc); if(server_version) free(server_version); //logp("end client\n"); return ret; }