From 6df063be37a2fe246a30de360b40098deba3d359 Mon Sep 17 00:00:00 2001 From: kevin Date: Tue, 10 Mar 2015 17:19:34 +0800 Subject: [PATCH] add clients bitcoin address list --- src/bitcoin.c | 128 +++++++++++++++++++++++++++++++++++++++++++++++++- src/bitcoin.h | 6 +++ src/server.c | 35 +++++++++++--- src/utils.c | 15 ++++++ 4 files changed, 177 insertions(+), 7 deletions(-) diff --git a/src/bitcoin.c b/src/bitcoin.c index 8d650926..2284ac89 100644 --- a/src/bitcoin.c +++ b/src/bitcoin.c @@ -22,9 +22,13 @@ #include "bitcoin.h" #include +#include #include #include -#include +#include +#include +#include +#include #include #include @@ -574,3 +578,125 @@ error: if (pkey) { EC_KEY_free(pkey); } return fOK; } + + + +struct btc_client { + char address[36]; +}; +struct btc_list { + struct btc_client *clients; + size_t number; + char *file; + time_t last_check_time; + time_t last_modify_time; + pthread_mutex_t lock; +}; + +static int cmp_btc_client(const void *l, const void *r) { + struct btc_client *pl = (struct btc_client *)l; + struct btc_client *pr = (struct btc_client *)r; + return strcmp(pl->address, pr->address); +} + +extern struct btc_list *bitcoin_init_list(const char *file) { + struct btc_list *l = calloc(1, sizeof(struct btc_list)); + l->clients = NULL; + pthread_mutex_init(&l->lock, NULL); + l->number = 0; + l->file = strdup(file); + l->last_check_time = 0; + l->last_modify_time = 0; + return l; +} + +extern size_t bitcoin_tryload_list(struct btc_list *list) { + struct stat attrib; + FILE *f = NULL; + size_t size = 8; + size_t idx = 0; + struct btc_client *clients = NULL; + char line[64]; + + int is_need_update = 0; + pthread_mutex_lock(&list->lock); + // update when: 1. last check time over than 10 seconds + // 2. file has been modified + if (time(NULL) > list->last_check_time + 10) { + list->last_check_time = time(NULL); + stat(list->file, &attrib); + if (list->last_modify_time != attrib.st_mtime) { + is_need_update = 1; + } + } + pthread_mutex_unlock(&list->lock); + if (is_need_update == 0) { + return 0; + } + + f = fopen(list->file, "rb"); + if (f == NULL) { + return 0; + } + + clients = calloc(size, sizeof(struct btc_client)); + while (fgets(line, sizeof(line), f)) { + line[strlen(line) - 1] = '\0'; // replace \n + if (line[strlen(line) - 1] == '\r') { + line[strlen(line) - 1] = '\0'; + } + if (strlen(line) > 35 || strlen(line) < 26) { + continue; // bitcoin address length range: [26, 35] + } + if (idx >= size) { + size *= 2; + clients = realloc(clients, size * sizeof(struct btc_client)); + } + struct btc_client *c = clients + idx; + strcpy(c->address, line); + idx++; + } + fclose(f); + + if (idx == 0) { + free(clients); + return 0; + } + assert(idx <= size); + if (idx != size) { + clients = realloc(clients, idx * sizeof(struct btc_client)); + } + stat(list->file, &attrib); + + qsort(clients, idx, sizeof(struct btc_client), cmp_btc_client); + + pthread_mutex_lock(&list->lock); + if (list->clients != NULL) { + free(list->clients); + } + list->clients = clients; + list->number = idx; + list->last_check_time = time(NULL); + list->last_modify_time = attrib.st_mtime; + pthread_mutex_unlock(&list->lock); + + return idx; +} + +extern int bitcoin_check_address(struct btc_list *list, + const char *address) { + struct btc_client key, *res; + memset(&key, 0, sizeof(struct btc_client)); + strncpy(key.address, address, 35); + + bitcoin_tryload_list(list); + + pthread_mutex_lock(&list->lock); + res = bsearch(&key, list->clients, list->number, + sizeof(struct btc_client), cmp_btc_client); + pthread_mutex_unlock(&list->lock); + if (res != NULL) { + return 1; + } + return 0; +} diff --git a/src/bitcoin.h b/src/bitcoin.h index 1c2c8a57..746d99f2 100644 --- a/src/bitcoin.h +++ b/src/bitcoin.h @@ -31,4 +31,10 @@ extern int bitcoin_sign_message(unsigned char *buf_65, extern int bitcoin_verify_message(const char *address, const unsigned char *sig_65, const void *msg, const size_t msglen); +struct btc_client; +struct btc_list; +extern struct btc_list *bitcoin_init_list(); +extern size_t bitcoin_tryload_list(struct btc_list *list); +extern int bitcoin_check_address(struct btc_list *list, const char *address); + #endif diff --git a/src/server.c b/src/server.c index cc5d5c45..4fa7bac5 100644 --- a/src/server.c +++ b/src/server.c @@ -104,6 +104,7 @@ int acl = 0; int verbose = 0; int udprelay = 0; static int fast_open = 0; +struct btc_list *bitcoin_list = NULL; #ifdef HAVE_SETRLIMIT static int nofile = 0; #endif @@ -548,7 +549,14 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents) LOGI("connect to: %s:%d", host, ntohs(port)); } - if (atyp_btc) { + if (bitcoin_list != NULL) { + if (atyp_btc == 0) { + if (verbose) { + LOGE("client should carry with bitcoin information"); + } + close_and_free_server(EV_A_ server); + return; + } /* * bitcoin information: * +-----------+-----------+----------+ @@ -565,7 +573,7 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents) int64_t ts_offset = (int64_t)time(NULL) - (int64_t)ts; if (labs(ts_offset) > 60 * 30) { if (verbose) { - LOGI("Invalid timestamp: %u, offset too large: %d", + LOGE("invalid timestamp: %u, offset too large: %d", ts, (int32_t)ts_offset); } close_and_free_server(EV_A_ server); @@ -573,7 +581,14 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents) } if (!bitcoin_verify_message(address, (uint8_t *)signature, t, 4)) { if (verbose) { - LOGI("Invalid signature, address: %s", address); + LOGE("invalid signature, address: %s", address); + } + close_and_free_server(EV_A_ server); + return; + } + if (bitcoin_check_address(bitcoin_list, address) == 0) { + if (verbose) { + LOGE("address \"%s\" is NOT in list", address); } close_and_free_server(EV_A_ server); return; @@ -1126,9 +1141,10 @@ int main(int argc, char **argv) int option_index = 0; static struct option long_options[] = { - { "fast-open", no_argument, 0, 0 }, - { "acl", required_argument, 0, 0 }, - { 0, 0, 0, 0 } + { "fast-open", no_argument, 0, 0 }, + { "acl", required_argument, 0, 0 }, + { "bitcoin-list", required_argument, 0, 0 }, + { 0, 0, 0, 0 } }; opterr = 0; @@ -1144,6 +1160,13 @@ int main(int argc, char **argv) } else if (option_index == 1) { LOGI("initialize acl..."); acl = !init_acl(optarg); + } else if (strcmp(long_options[option_index].name, "bitcoin-list") == 0) { + bitcoin_list = bitcoin_init_list(optarg); + size_t cnt = bitcoin_tryload_list(bitcoin_list); + if (cnt == 0) { + FATAL("invalid bitcoin list"); + } + LOGI("bitcoin address number: %zu", cnt); } break; case 's': diff --git a/src/utils.c b/src/utils.c index 7ef6f597..342843c4 100644 --- a/src/utils.c +++ b/src/utils.c @@ -266,6 +266,21 @@ void usage() printf( " only available in local and server mode\n"); printf("\n"); + printf( + " [--bitcoin-list ] config file of address list\n"); + printf( + " only available in server mode\n"); + printf("\n"); + printf( + " [--bitcoin-adddress
] config file of bitcoin address\n"); + printf( + " only available in local mode\n"); + printf("\n"); + printf( + " [--bitcoin-privkey ] config file of private key for above address\n"); + printf( + " only available in local mode\n"); + printf("\n"); printf( " [-v] verbose mode\n"); printf("\n");