Browse Source

Merge branch 'release/add_bitcoin'

pull/286/head
kevin 10 years ago
parent
commit
1ba5e26cfc
9 changed files with 956 additions and 40 deletions
  1. 46
      src/Makefile.am
  2. 54
      src/Makefile.in
  3. 702
      src/bitcoin.c
  4. 40
      src/bitcoin.h
  5. 5
      src/jconf.c
  6. 2
      src/jconf.h
  7. 59
      src/local.c
  8. 73
      src/server.c
  9. 15
      src/utils.c

46
src/Makefile.am

@ -10,10 +10,10 @@ AM_CFLAGS += -I$(top_srcdir)/libsodium/src/libsodium/include
AM_LDFLAGS = -static
SS_COMMON_LIBS = $(top_builddir)/libev/libev.la \
$(top_builddir)/libipset/libipset.la \
$(top_builddir)/libcork/libcork.la \
$(top_builddir)/libsodium/src/libsodium/libsodium.la \
$(INET_NTOP_LIB)
$(top_builddir)/libipset/libipset.la \
$(top_builddir)/libcork/libcork.la \
$(top_builddir)/libsodium/src/libsodium/libsodium.la \
$(INET_NTOP_LIB)
bin_PROGRAMS = ss-local ss-tunnel
if !BUILD_WINCOMPAT
@ -23,30 +23,32 @@ endif
ss_local_SOURCES = utils.c \
jconf.c \
json.c \
encrypt.c \
udprelay.c \
cache.c \
acl.c \
netutils.c \
local.c
encrypt.c \
udprelay.c \
cache.c \
acl.c \
netutils.c \
bitcoin.c \
local.c
ss_tunnel_SOURCES = utils.c \
jconf.c \
json.c \
encrypt.c \
udprelay.c \
cache.c \
netutils.c \
tunnel.c
jconf.c \
json.c \
encrypt.c \
udprelay.c \
cache.c \
netutils.c \
tunnel.c
ss_server_SOURCES = utils.c \
jconf.c \
json.c \
encrypt.c \
udprelay.c \
cache.c \
acl.c \
resolv.c \
udprelay.c \
cache.c \
acl.c \
resolv.c \
bitcoin.c \
server.c
ss_local_LDADD = $(SS_COMMON_LIBS)
@ -71,7 +73,7 @@ ss_redir_SOURCES = utils.c \
jconf.c \
json.c \
encrypt.c \
netutils.c \
netutils.c \
redir.c
ss_redir_LDADD = $(SS_COMMON_LIBS)
ss_redir_LDADD += $(top_builddir)/libudns/libudns.la

54
src/Makefile.in

@ -115,7 +115,7 @@ am__DEPENDENCIES_3 = $(am__DEPENDENCIES_2) \
$(top_builddir)/libudns/libudns.la
libshadowsocks_la_DEPENDENCIES = $(am__DEPENDENCIES_3)
am__libshadowsocks_la_SOURCES_DIST = utils.c jconf.c json.c encrypt.c \
udprelay.c cache.c acl.c netutils.c local.c win32.c
udprelay.c cache.c acl.c netutils.c bitcoin.c local.c win32.c
@BUILD_WINCOMPAT_TRUE@am__objects_1 = libshadowsocks_la-win32.lo
am__objects_2 = libshadowsocks_la-utils.lo libshadowsocks_la-jconf.lo \
libshadowsocks_la-json.lo libshadowsocks_la-encrypt.lo \
@ -135,14 +135,14 @@ libshadowsocks_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
@BUILD_REDIRECTOR_TRUE@am__EXEEXT_2 = ss-redir$(EXEEXT)
PROGRAMS = $(bin_PROGRAMS)
am__ss_local_SOURCES_DIST = utils.c jconf.c json.c encrypt.c \
udprelay.c cache.c acl.c netutils.c local.c win32.c
udprelay.c cache.c acl.c netutils.c bitcoin.c local.c win32.c
@BUILD_WINCOMPAT_TRUE@am__objects_3 = ss_local-win32.$(OBJEXT)
am_ss_local_OBJECTS = ss_local-utils.$(OBJEXT) \
ss_local-jconf.$(OBJEXT) ss_local-json.$(OBJEXT) \
ss_local-encrypt.$(OBJEXT) ss_local-udprelay.$(OBJEXT) \
ss_local-cache.$(OBJEXT) ss_local-acl.$(OBJEXT) \
ss_local-netutils.$(OBJEXT) ss_local-local.$(OBJEXT) \
$(am__objects_3)
ss_local-netutils.$(OBJEXT) ss_local-bitcoin.$(OBJEXT) \
ss_local-local.$(OBJEXT) $(am__objects_3)
ss_local_OBJECTS = $(am_ss_local_OBJECTS)
ss_local_DEPENDENCIES = $(am__DEPENDENCIES_2) \
$(top_builddir)/libudns/libudns.la
@ -162,7 +162,8 @@ am_ss_server_OBJECTS = ss_server-utils.$(OBJEXT) \
ss_server-jconf.$(OBJEXT) ss_server-json.$(OBJEXT) \
ss_server-encrypt.$(OBJEXT) ss_server-udprelay.$(OBJEXT) \
ss_server-cache.$(OBJEXT) ss_server-acl.$(OBJEXT) \
ss_server-resolv.$(OBJEXT) ss_server-server.$(OBJEXT)
ss_server-resolv.$(OBJEXT) ss_server-bitcoin.$(OBJEXT) \
ss_server-server.$(OBJEXT)
ss_server_OBJECTS = $(am_ss_server_OBJECTS)
ss_server_DEPENDENCIES = $(am__DEPENDENCIES_2) \
$(top_builddir)/libudns/libudns.la
@ -359,7 +360,7 @@ SS_COMMON_LIBS = $(top_builddir)/libev/libev.la \
$(INET_NTOP_LIB)
ss_local_SOURCES = utils.c jconf.c json.c encrypt.c udprelay.c cache.c \
acl.c netutils.c local.c $(am__append_2)
acl.c netutils.c bitcoin.c local.c $(am__append_2)
ss_tunnel_SOURCES = utils.c jconf.c json.c encrypt.c udprelay.c \
cache.c netutils.c tunnel.c $(am__append_3)
ss_server_SOURCES = utils.c \
@ -370,6 +371,7 @@ ss_server_SOURCES = utils.c \
cache.c \
acl.c \
resolv.c \
bitcoin.c \
server.c
ss_local_LDADD = $(SS_COMMON_LIBS) $(top_builddir)/libudns/libudns.la
@ -382,7 +384,7 @@ ss_server_CFLAGS = $(AM_CFLAGS) -DUDPRELAY_REMOTE
@BUILD_REDIRECTOR_TRUE@ jconf.c \
@BUILD_REDIRECTOR_TRUE@ json.c \
@BUILD_REDIRECTOR_TRUE@ encrypt.c \
@BUILD_REDIRECTOR_TRUE@ netutils.c \
@BUILD_REDIRECTOR_TRUE@ netutils.c \
@BUILD_REDIRECTOR_TRUE@ redir.c
@BUILD_REDIRECTOR_TRUE@ss_redir_LDADD = $(SS_COMMON_LIBS) \
@ -530,6 +532,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jconf.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/json.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libshadowsocks_la-acl.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libshadowsocks_la-bitcoin.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libshadowsocks_la-cache.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libshadowsocks_la-encrypt.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libshadowsocks_la-jconf.Plo@am__quote@
@ -542,6 +545,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netutils.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/redir.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss_local-acl.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss_local-bitcoin.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss_local-cache.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss_local-encrypt.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss_local-jconf.Po@am__quote@
@ -552,6 +556,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss_local-utils.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss_local-win32.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss_server-acl.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss_server-bitcoin.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss_server-cache.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss_server-encrypt.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss_server-jconf.Po@am__quote@
@ -651,6 +656,13 @@ libshadowsocks_la-netutils.lo: netutils.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libshadowsocks_la_CFLAGS) $(CFLAGS) -c -o libshadowsocks_la-netutils.lo `test -f 'netutils.c' || echo '$(srcdir)/'`netutils.c
libshadowsocks_la-bitcoin.lo: bitcoin.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libshadowsocks_la_CFLAGS) $(CFLAGS) -MT libshadowsocks_la-bitcoin.lo -MD -MP -MF $(DEPDIR)/libshadowsocks_la-bitcoin.Tpo -c -o libshadowsocks_la-bitcoin.lo `test -f 'bitcoin.c' || echo '$(srcdir)/'`bitcoin.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libshadowsocks_la-bitcoin.Tpo $(DEPDIR)/libshadowsocks_la-bitcoin.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='bitcoin.c' object='libshadowsocks_la-bitcoin.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libshadowsocks_la_CFLAGS) $(CFLAGS) -c -o libshadowsocks_la-bitcoin.lo `test -f 'bitcoin.c' || echo '$(srcdir)/'`bitcoin.c
libshadowsocks_la-local.lo: local.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libshadowsocks_la_CFLAGS) $(CFLAGS) -MT libshadowsocks_la-local.lo -MD -MP -MF $(DEPDIR)/libshadowsocks_la-local.Tpo -c -o libshadowsocks_la-local.lo `test -f 'local.c' || echo '$(srcdir)/'`local.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libshadowsocks_la-local.Tpo $(DEPDIR)/libshadowsocks_la-local.Plo
@ -777,6 +789,20 @@ ss_local-netutils.obj: netutils.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_local_CFLAGS) $(CFLAGS) -c -o ss_local-netutils.obj `if test -f 'netutils.c'; then $(CYGPATH_W) 'netutils.c'; else $(CYGPATH_W) '$(srcdir)/netutils.c'; fi`
ss_local-bitcoin.o: bitcoin.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_local_CFLAGS) $(CFLAGS) -MT ss_local-bitcoin.o -MD -MP -MF $(DEPDIR)/ss_local-bitcoin.Tpo -c -o ss_local-bitcoin.o `test -f 'bitcoin.c' || echo '$(srcdir)/'`bitcoin.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ss_local-bitcoin.Tpo $(DEPDIR)/ss_local-bitcoin.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='bitcoin.c' object='ss_local-bitcoin.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_local_CFLAGS) $(CFLAGS) -c -o ss_local-bitcoin.o `test -f 'bitcoin.c' || echo '$(srcdir)/'`bitcoin.c
ss_local-bitcoin.obj: bitcoin.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_local_CFLAGS) $(CFLAGS) -MT ss_local-bitcoin.obj -MD -MP -MF $(DEPDIR)/ss_local-bitcoin.Tpo -c -o ss_local-bitcoin.obj `if test -f 'bitcoin.c'; then $(CYGPATH_W) 'bitcoin.c'; else $(CYGPATH_W) '$(srcdir)/bitcoin.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ss_local-bitcoin.Tpo $(DEPDIR)/ss_local-bitcoin.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='bitcoin.c' object='ss_local-bitcoin.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_local_CFLAGS) $(CFLAGS) -c -o ss_local-bitcoin.obj `if test -f 'bitcoin.c'; then $(CYGPATH_W) 'bitcoin.c'; else $(CYGPATH_W) '$(srcdir)/bitcoin.c'; fi`
ss_local-local.o: local.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_local_CFLAGS) $(CFLAGS) -MT ss_local-local.o -MD -MP -MF $(DEPDIR)/ss_local-local.Tpo -c -o ss_local-local.o `test -f 'local.c' || echo '$(srcdir)/'`local.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ss_local-local.Tpo $(DEPDIR)/ss_local-local.Po
@ -917,6 +943,20 @@ ss_server-resolv.obj: resolv.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -c -o ss_server-resolv.obj `if test -f 'resolv.c'; then $(CYGPATH_W) 'resolv.c'; else $(CYGPATH_W) '$(srcdir)/resolv.c'; fi`
ss_server-bitcoin.o: bitcoin.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -MT ss_server-bitcoin.o -MD -MP -MF $(DEPDIR)/ss_server-bitcoin.Tpo -c -o ss_server-bitcoin.o `test -f 'bitcoin.c' || echo '$(srcdir)/'`bitcoin.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ss_server-bitcoin.Tpo $(DEPDIR)/ss_server-bitcoin.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='bitcoin.c' object='ss_server-bitcoin.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -c -o ss_server-bitcoin.o `test -f 'bitcoin.c' || echo '$(srcdir)/'`bitcoin.c
ss_server-bitcoin.obj: bitcoin.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -MT ss_server-bitcoin.obj -MD -MP -MF $(DEPDIR)/ss_server-bitcoin.Tpo -c -o ss_server-bitcoin.obj `if test -f 'bitcoin.c'; then $(CYGPATH_W) 'bitcoin.c'; else $(CYGPATH_W) '$(srcdir)/bitcoin.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ss_server-bitcoin.Tpo $(DEPDIR)/ss_server-bitcoin.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='bitcoin.c' object='ss_server-bitcoin.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -c -o ss_server-bitcoin.obj `if test -f 'bitcoin.c'; then $(CYGPATH_W) 'bitcoin.c'; else $(CYGPATH_W) '$(srcdir)/bitcoin.c'; fi`
ss_server-server.o: server.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -MT ss_server-server.o -MD -MP -MF $(DEPDIR)/ss_server-server.Tpo -c -o ss_server-server.o `test -f 'server.c' || echo '$(srcdir)/'`server.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ss_server-server.Tpo $(DEPDIR)/ss_server-server.Po

702
src/bitcoin.c

@ -0,0 +1,702 @@
/*
* bitcoin.c
*
* Copyright (C) 2015, Kevin Pan <bit.kevin@gmail.com>
*
* This file is part of the shadowsocks-libev.
*
* shadowsocks-libev is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* shadowsocks-libev is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with shadowsocks-libev; see the file COPYING. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include "bitcoin.h"
#include <assert.h>
#include <inttypes.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pthread.h>
#include <unistd.h>
#include <openssl/bn.h>
#include <openssl/ecdsa.h>
#include <openssl/evp.h>
#include <openssl/ripemd.h>
#include <openssl/sha.h>
//
// address prefix
// @see https://en.bitcoin.it/wiki/List_of_address_prefixes
//
#define BITCOIN_ADDRESS_PREFIX_PUBKEY 0x00
#define BITCOIN_ADDRESS_PREFIX_PUBKEY_TESTNET 0x6F
#define BITCOIN_PUBKEY_UNCOMPRESSED 0x00
#define BITCOIN_PUBKEY_COMPRESSED 0x01
#define skip_char(c) \
(((c) == '\r') || ((c) == '\n') || ((c) == ' ') || ((c) == '\t'))
const char *vg_b58_alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
const signed char vg_b58_reverse_map[256] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, -1, -1, -1, -1, -1, -1,
-1, 9, 10, 11, 12, 13, 14, 15, 16, -1, 17, 18, 19, 20, 21, -1,
22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, -1, -1, -1, -1, -1,
-1, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, -1, 44, 45, 46,
47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
};
static int vg_b58_decode_check(const char *input, void *buf, size_t len) {
int i, l, c;
unsigned char *xbuf = NULL;
BIGNUM bn, bnw, bnbase;
BN_CTX *bnctx;
unsigned char hash1[32], hash2[32];
int zpfx;
int res = 0;
BN_init(&bn);
BN_init(&bnw);
BN_init(&bnbase);
BN_set_word(&bnbase, 58);
bnctx = BN_CTX_new();
/* Build a bignum from the encoded value */
l = strlen(input);
for (i = 0; i < l; i++) {
if (skip_char(input[i]))
continue;
c = vg_b58_reverse_map[(int)input[i]];
if (c < 0)
goto out;
BN_clear(&bnw);
BN_set_word(&bnw, c);
BN_mul(&bn, &bn, &bnbase, bnctx);
BN_add(&bn, &bn, &bnw);
}
/* Copy the bignum to a byte buffer */
for (i = 0, zpfx = 0; input[i]; i++) {
if (skip_char(input[i]))
continue;
if (input[i] != vg_b58_alphabet[0])
break;
zpfx++;
}
c = BN_num_bytes(&bn);
l = zpfx + c;
if (l < 5)
goto out;
xbuf = (unsigned char *) malloc(l);
if (!xbuf)
goto out;
if (zpfx)
memset(xbuf, 0, zpfx);
if (c)
BN_bn2bin(&bn, xbuf + zpfx);
/* Check the hash code */
l -= 4;
SHA256(xbuf, l, hash1);
SHA256(hash1, sizeof(hash1), hash2);
if (memcmp(hash2, xbuf + l, 4))
goto out;
/* Buffer verified */
if (len) {
if (len > l)
len = l;
memcpy(buf, xbuf, len);
}
res = l;
out:
if (xbuf)
free(xbuf);
BN_clear_free(&bn);
BN_clear_free(&bnw);
BN_clear_free(&bnbase);
BN_CTX_free(bnctx);
return res;
}
static void vg_b58_encode_check(void *buf, size_t len, char *result)
{
unsigned char hash1[32];
unsigned char hash2[32];
int d, p;
BN_CTX *bnctx;
BIGNUM *bn, *bndiv, *bntmp;
BIGNUM bna, bnb, bnbase, bnrem;
unsigned char *binres;
int brlen, zpfx;
bnctx = BN_CTX_new();
BN_init(&bna);
BN_init(&bnb);
BN_init(&bnbase);
BN_init(&bnrem);
BN_set_word(&bnbase, 58);
bn = &bna;
bndiv = &bnb;
brlen = (2 * len) + 4;
binres = (unsigned char*) malloc(brlen);
memcpy(binres, buf, len);
SHA256(binres, len, hash1);
SHA256(hash1, sizeof(hash1), hash2);
memcpy(&binres[len], hash2, 4);
BN_bin2bn(binres, len + 4, bn);
for (zpfx = 0; zpfx < (len + 4) && binres[zpfx] == 0; zpfx++);
p = (int)brlen;
while (!BN_is_zero(bn)) {
BN_div(bndiv, &bnrem, bn, &bnbase, bnctx);
bntmp = bn;
bn = bndiv;
bndiv = bntmp;
d = BN_get_word(&bnrem);
binres[--p] = vg_b58_alphabet[d];
}
while (zpfx--) {
binres[--p] = vg_b58_alphabet[0];
}
memcpy(result, &binres[p], brlen - p);
result[brlen - p] = '\0';
free(binres);
BN_clear_free(&bna);
BN_clear_free(&bnb);
BN_clear_free(&bnbase);
BN_clear_free(&bnrem);
BN_CTX_free(bnctx);
}
static void vg_encode_address(const EC_POINT *ppoint, const EC_GROUP *pgroup,
point_conversion_form_t form, int addr_type, char *result)
{
unsigned char eckey_buf[128] = {0};
unsigned char binres[21] = {0,};
unsigned char hash1[32];
size_t len = 0;
len = EC_POINT_point2oct(pgroup, ppoint, form,
eckey_buf, sizeof(eckey_buf), NULL);
binres[0] = addr_type;
SHA256(eckey_buf, len, hash1);
RIPEMD160(hash1, sizeof(hash1), &binres[1]);
vg_b58_encode_check(binres, sizeof(binres), result);
}
static size_t write_compact_size(const uint64_t val, uint8_t *dest) {
if (val < 0xfd) {
*dest++ = (unsigned char)val;
return 1;
} else if (val <= 0xffff) {
*dest++ = 0xfd;
*(uint16_t *)dest = (uint16_t)val;
return 2;
} else if (val <= 0xffffffff) {
*dest++ = 0xfe;
*(uint32_t *)dest = (uint32_t)val;
return 4;
} else {
*dest++ = 0xff;
*(uint64_t *)dest = (uint64_t)val;
return 8;
}
return 0;
}
static void dsha265_message(uint8_t *hash,
const uint8_t *msg, const size_t len_msg) {
const char *magic = "Bitcoin Signed Message:\n"; // bitcoin message magic
const size_t len_magic = strlen(magic);
size_t buf_size = len_magic + len_msg + 9/*max_compact_size*/ * 2;
char *buf = (char *)malloc(buf_size);
size_t buf_len = 0;
memset(buf, 0, buf_size);
buf_len += write_compact_size(len_magic, (uint8_t *)buf);
memcpy(buf + buf_len, magic, len_magic);
buf_len += len_magic;
buf_len += write_compact_size(len_msg, (uint8_t *)buf + buf_len);
memcpy(buf + buf_len, msg, len_msg);
buf_len += len_msg;
assert(buf_len <= buf_size);
uint8_t hash1[32];
SHA256((uint8_t *)buf, buf_len, hash1);
SHA256(hash1, sizeof(hash1), hash);
free(buf);
}
static int EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key) {
int ok = 0;
BN_CTX *ctx = NULL;
EC_POINT *pub_key = NULL;
if (!eckey) return 0;
const EC_GROUP *group = EC_KEY_get0_group(eckey);
if ((ctx = BN_CTX_new()) == NULL)
goto err;
pub_key = EC_POINT_new(group);
if (pub_key == NULL)
goto err;
if (!EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, ctx))
goto err;
EC_KEY_set_private_key(eckey,priv_key);
EC_KEY_set_public_key(eckey,pub_key);
ok = 1;
err:
if (pub_key)
EC_POINT_free(pub_key);
if (ctx != NULL)
BN_CTX_free(ctx);
return ok;
}
// Perform ECDSA key recovery (see SEC1 4.1.6) for curves over (mod p)-fields
// recid selects which key is recovered
// if check is non-zero, additional checks are performed
static int ECDSA_SIG_recover_key_GFp(EC_KEY *eckey, ECDSA_SIG *ecsig,
const unsigned char *msg,
int msglen, int recid, int check) {
if (!eckey) return 0;
int ret = 0;
BN_CTX *ctx = NULL;
BIGNUM *x = NULL;
BIGNUM *e = NULL;
BIGNUM *order = NULL;
BIGNUM *sor = NULL;
BIGNUM *eor = NULL;
BIGNUM *field = NULL;
EC_POINT *R = NULL;
EC_POINT *O = NULL;
EC_POINT *Q = NULL;
BIGNUM *rr = NULL;
BIGNUM *zero = NULL;
int n = 0;
int i = recid / 2;
const EC_GROUP *group = EC_KEY_get0_group(eckey);
if ((ctx = BN_CTX_new()) == NULL) { ret = -1; goto err; }
BN_CTX_start(ctx);
order = BN_CTX_get(ctx);
if (!EC_GROUP_get_order(group, order, ctx)) { ret = -2; goto err; }
x = BN_CTX_get(ctx);
if (!BN_copy(x, order)) { ret=-1; goto err; }
if (!BN_mul_word(x, i)) { ret=-1; goto err; }
if (!BN_add(x, x, ecsig->r)) { ret=-1; goto err; }
field = BN_CTX_get(ctx);
if (!EC_GROUP_get_curve_GFp(group, field, NULL, NULL, ctx)) { ret=-2; goto err; }
if (BN_cmp(x, field) >= 0) { ret=0; goto err; }
if ((R = EC_POINT_new(group)) == NULL) { ret = -2; goto err; }
if (!EC_POINT_set_compressed_coordinates_GFp(group, R, x, recid % 2, ctx)) { ret=0; goto err; }
if (check) {
if ((O = EC_POINT_new(group)) == NULL) { ret = -2; goto err; }
if (!EC_POINT_mul(group, O, NULL, R, order, ctx)) { ret=-2; goto err; }
if (!EC_POINT_is_at_infinity(group, O)) { ret = 0; goto err; }
}
if ((Q = EC_POINT_new(group)) == NULL) { ret = -2; goto err; }
n = EC_GROUP_get_degree(group);
e = BN_CTX_get(ctx);
if (!BN_bin2bn(msg, msglen, e)) { ret=-1; goto err; }
if (8*msglen > n) BN_rshift(e, e, 8-(n & 7));
zero = BN_CTX_get(ctx);
if (!BN_zero(zero)) { ret=-1; goto err; }
if (!BN_mod_sub(e, zero, e, order, ctx)) { ret=-1; goto err; }
rr = BN_CTX_get(ctx);
if (!BN_mod_inverse(rr, ecsig->r, order, ctx)) { ret=-1; goto err; }
sor = BN_CTX_get(ctx);
if (!BN_mod_mul(sor, ecsig->s, rr, order, ctx)) { ret=-1; goto err; }
eor = BN_CTX_get(ctx);
if (!BN_mod_mul(eor, e, rr, order, ctx)) { ret=-1; goto err; }
if (!EC_POINT_mul(group, Q, eor, R, sor, ctx)) { ret=-2; goto err; }
if (!EC_KEY_set_public_key(eckey, Q)) { ret=-2; goto err; }
ret = 1;
err:
if (ctx) {
BN_CTX_end(ctx);
BN_CTX_free(ctx);
}
if (R != NULL) EC_POINT_free(R);
if (O != NULL) EC_POINT_free(O);
if (Q != NULL) EC_POINT_free(Q);
return ret;
}
static int priv_key_b58_to_address(const char *priv_key_b58,
const int is_compressed_pubkey,
const int addr_type,
char *address) {
EC_KEY *pkey = NULL;
unsigned char buf[128] = {0};
uint8_t pubKey[65]; // public key max size is 65 bytes
char ecprot[128];
unsigned char *pbegin = NULL;
int res, pubkey_size = 0;
int fOk = 0;
pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
EC_KEY_set_conv_form(pkey, is_compressed_pubkey ?
POINT_CONVERSION_COMPRESSED : POINT_CONVERSION_UNCOMPRESSED);
// import secret
vg_b58_decode_check(priv_key_b58, buf, 33);
BIGNUM *bn = BN_bin2bn(buf + 1, 32, BN_new());
res = EC_KEY_regenerate_key(pkey, bn);
BN_clear_free(bn);
if (!res){ goto error; }
// get pubkey
pubkey_size = i2o_ECPublicKey(pkey, NULL);
if (!pubkey_size) { goto error; }
pbegin = pubKey;
if (i2o_ECPublicKey(pkey, &pbegin) != pubkey_size) { goto error; }
// encode address
vg_encode_address(EC_KEY_get0_public_key(pkey),
EC_KEY_get0_group(pkey),
is_compressed_pubkey ?
POINT_CONVERSION_COMPRESSED : POINT_CONVERSION_UNCOMPRESSED,
addr_type, ecprot);
strcpy(address, ecprot);
fOk = 1;
error:
if (pkey) { EC_KEY_free(pkey); }
return fOk;
}
//
// return:
// -1 : invalid private key
// 1 : compressed
// 0 : uncompressed
static int isCompressedAddress(const char *priv_key_b58, const char *address) {
int is_compressed_pubkey;
char buf[64];
int res;
// try compressed
is_compressed_pubkey = 1;
memset(buf, 0, sizeof(buf));
res = priv_key_b58_to_address(priv_key_b58, is_compressed_pubkey,
BITCOIN_ADDRESS_PREFIX_PUBKEY, buf);
if (res != 1) { return -1; }
if (memcmp(buf, address, strlen(address)) == 0) {
return 1; // compressed
}
// try uncompressed
is_compressed_pubkey = 0;
memset(buf, 0, sizeof(buf));
res = priv_key_b58_to_address(priv_key_b58, is_compressed_pubkey,
BITCOIN_ADDRESS_PREFIX_PUBKEY, buf);
if (res != 1) { return -1; }
if (memcmp(buf, address, strlen(address)) == 0) {
return 0; // uncompressed
}
return -1;
}
static int sign_message(uint8_t *signature_65,
const uint8_t *msg, const size_t msg_len,
const char *priv_key_b58, int is_compressed_pubkey) {
EC_KEY *pkey = NULL;
ECDSA_SIG *sig = NULL;
EC_KEY *eckey = NULL; // recover key
uint8_t pubKey[65]; // public key max size is 65 bytes
uint8_t pubKey_rc[65];
int pubkey_size, pubkey_rc_size;
uint8_t sigbuf[65];
unsigned char *pbegin = NULL;
unsigned char buf[128] = {0};
int res, fOK = 0;
int nBitsR, nBitsS;
unsigned char hash[32];
dsha265_message(hash, msg, msg_len); // message double sha256
pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
EC_KEY_set_conv_form(pkey, is_compressed_pubkey ?
POINT_CONVERSION_COMPRESSED : POINT_CONVERSION_UNCOMPRESSED);
// import secret
vg_b58_decode_check(priv_key_b58, buf, 33);
BIGNUM *bn = BN_bin2bn(buf + 1, 32, BN_new());
res = EC_KEY_regenerate_key(pkey, bn);
BN_clear_free(bn);
memset(buf, 0, sizeof(buf));
if (!res){ goto error; }
// get pubkey
pubkey_size = i2o_ECPublicKey(pkey, NULL);
if (!pubkey_size) { goto error; }
pbegin = pubKey;
if (i2o_ECPublicKey(pkey, &pbegin) != pubkey_size) { goto error; }
// do sign
sig = ECDSA_do_sign(hash, sizeof(hash), pkey);
if (!sig) { goto error; }
nBitsR = BN_num_bits(sig->r);
nBitsS = BN_num_bits(sig->s);
if (nBitsR <= 256 && nBitsS <= 256) {
int nRecId = -1;
int i;
eckey = EC_KEY_new_by_curve_name(NID_secp256k1);
EC_KEY_set_conv_form(eckey, is_compressed_pubkey ?
POINT_CONVERSION_COMPRESSED : POINT_CONVERSION_UNCOMPRESSED);
for (i = 0; i < 4; i++) {
if (ECDSA_SIG_recover_key_GFp(eckey, sig, (unsigned char*)hash,
sizeof(hash), i, 1) == 1) {
// get recover pubkey
pubkey_rc_size = i2o_ECPublicKey(pkey, NULL);
if (!pubkey_rc_size) { goto error; }
pbegin = pubKey_rc;
if (i2o_ECPublicKey(eckey, &pbegin) != pubkey_rc_size) {
goto error;
}
// check recover key
if (pubkey_size == pubkey_rc_size &&
memcmp(pubKey, pubKey_rc, pubkey_rc_size) == 0) {
nRecId = i;
break;
}
}
}
if (nRecId == -1) { goto error; }
sigbuf[0] = nRecId + 27 + (is_compressed_pubkey ? 4 : 0);
BN_bn2bin(sig->r, sigbuf + 33 - (nBitsR+7)/8);
BN_bn2bin(sig->s, sigbuf + 65 - (nBitsS+7)/8);
memcpy(signature_65, sigbuf, 65);
fOK = 1;
}
error:
if (pkey) { EC_KEY_free(pkey); }
if (eckey) { EC_KEY_free(eckey); }
if (sig) { ECDSA_SIG_free(sig); }
return fOK;
}
int bitcoin_sign_message(unsigned char *buf_65,
const void *msg, const size_t msg_len,
const char *priv_key_b58, const char *address) {
int is_compressed = isCompressedAddress(priv_key_b58, address);
return sign_message(buf_65, (uint8_t *)msg, msg_len,
priv_key_b58, is_compressed);
}
int bitcoin_verify_message(const char *address, const unsigned char *sig,
const void *msg, const size_t msglen) {
EC_KEY *pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
uint8_t hash[32] = {0};
char ecprot[128] = {0};
int fOK = 0;
// message double sha256
dsha265_message(hash, msg, msglen);
// recover
ECDSA_SIG *esig = ECDSA_SIG_new();
BN_bin2bn(&sig[1], 32, esig->r);
BN_bin2bn(&sig[33], 32, esig->s);
int ret = ECDSA_SIG_recover_key_GFp(pkey, esig, hash, sizeof(hash),
((sig[0] - 27) & ~4), 0) == 1;
ECDSA_SIG_free(esig);
if (!ret) { goto error; }
int is_compressed_pubkey = (sig[0] - 27) & 4;
// encode address
vg_encode_address(EC_KEY_get0_public_key(pkey),
EC_KEY_get0_group(pkey),
is_compressed_pubkey ?
POINT_CONVERSION_COMPRESSED : POINT_CONVERSION_UNCOMPRESSED,
BITCOIN_ADDRESS_PREFIX_PUBKEY, ecprot);
if (memcmp(address, ecprot, strlen(address)) == 0) {
fOK = 1;
}
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;
}

40
src/bitcoin.h

@ -0,0 +1,40 @@
/*
* bitcoin.h
*
* Copyright (C) 2015, Kevin Pan <bit.kevin@gmail.com>
*
* This file is part of the shadowsocks-libev.
*
* shadowsocks-libev is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* shadowsocks-libev is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with shadowsocks-libev; see the file COPYING. If not, see
* <http://www.gnu.org/licenses/>.
*/
#ifndef _BITCOIN_H
#define _BITCOIN_H
#include <stddef.h>
extern int bitcoin_sign_message(unsigned char *buf_65,
const void *msg, const size_t msg_len,
const char *priv_key_b58, const char *address);
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

5
src/jconf.c

@ -101,6 +101,7 @@ jconf_t *read_jconf(const char * file)
{
static jconf_t conf;
memset(&conf, 0, sizeof(conf));
char *buf;
json_value *obj;
@ -177,6 +178,10 @@ jconf_t *read_jconf(const char * file)
conf.nofile = value->u.integer;
} else if (strcmp(name, "nameserver") == 0) {
conf.nameserver = to_string(value);
} else if (strcmp(name, "bitcoin_address") == 0) {
conf.bitcoin_address = to_string(value);
} else if (strcmp(name, "bitcoin_privkey") == 0) {
conf.bitcoin_privkey = to_string(value);
}
}
} else {

2
src/jconf.h

@ -45,6 +45,8 @@ typedef struct {
int fast_open;
int nofile;
char *nameserver;
char *bitcoin_address;
char *bitcoin_privkey;
} jconf_t;
jconf_t *read_jconf(const char * file);

59
src/local.c

@ -66,6 +66,7 @@
#include "socks5.h"
#include "acl.h"
#include "local.h"
#include "bitcoin.h"
#ifndef EAGAIN
#define EAGAIN EWOULDBLOCK
@ -82,6 +83,8 @@
int acl = 0;
int verbose = 0;
int udprelay = 0;
char *bitcoin_address = NULL;
char *bitcoin_privkey = NULL;
static int fast_open = 0;
#ifdef HAVE_SETRLIMIT
#ifndef LIB_ONLY
@ -364,7 +367,7 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents)
return;
} else {
char host[256], port[16];
char ss_addr_to_send[320];
char ss_addr_to_send[450];
ssize_t addr_len = 0;
ss_addr_to_send[addr_len++] = request->atyp;
@ -420,10 +423,42 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents)
return;
}
// add bitcoin infomation to `ss_addr_to_send`
size_t bitcoin_len = 0;
if (bitcoin_address != NULL && bitcoin_privkey != NULL) {
/*
* bitcoin information:
* +-----------+-----------+----------+
* | Signature | Timestamp | Address |
* +-----------+-----------+----------+
* | 65 | 4 | String |
* +-----------+-----------+----------+
*/
uint32_t now = (uint32_t)time(NULL);
uint8_t msg[4] = {(uint8_t)(now >> 24), (uint8_t)(now >> 16),
(uint8_t)(now >> 8), (uint8_t)(now >> 0)};
uint8_t sig[65] = {0}; // signature buf size always 65 bytes
if (!bitcoin_sign_message(sig, msg, sizeof(msg), bitcoin_privkey, bitcoin_address)) {
FATAL("bitcoin sign message fail");
}
size_t addr_len_ori = addr_len;
memcpy(ss_addr_to_send + addr_len, sig, 65);
addr_len += 65;
memcpy(ss_addr_to_send + addr_len, msg, sizeof(msg));
addr_len += 4;
memcpy(ss_addr_to_send + addr_len, bitcoin_address, strlen(bitcoin_address));
addr_len += strlen(bitcoin_address);
ss_addr_to_send[addr_len++] = '\0';
bitcoin_len = addr_len - addr_len_ori;
ss_addr_to_send[0] |= 0x10; // set bitcoin flag
}
server->stage = 5;
r -= (3 + addr_len);
buf += (3 + addr_len);
// bitcoin information is extra, so minus it's length
r -= (3 + addr_len - bitcoin_len);
buf += (3 + addr_len - bitcoin_len);
if (verbose) {
LOGI("connect to %s:%s", host, port);
@ -892,9 +927,11 @@ 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-address", required_argument, 0, 0 },
{ "bitcoin-privkey", required_argument, 0, 0 },
{ 0, 0, 0, 0 }
};
opterr = 0;
@ -910,6 +947,10 @@ 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-address") == 0) {
bitcoin_address = optarg;
} else if (strcmp(long_options[option_index].name, "bitcoin-privkey") == 0) {
bitcoin_privkey = optarg;
}
break;
case 's':
@ -994,6 +1035,12 @@ int main(int argc, char **argv)
if (timeout == NULL) {
timeout = conf->timeout;
}
if (bitcoin_address == NULL) {
bitcoin_address = conf->bitcoin_address;
}
if (bitcoin_privkey == NULL) {
bitcoin_privkey = conf->bitcoin_privkey;
}
if (fast_open == 0) {
fast_open = conf->fast_open;
}

73
src/server.c

@ -62,6 +62,7 @@
#include "utils.h"
#include "acl.h"
#include "server.h"
#include "bitcoin.h"
#ifndef EAGAIN
#define EAGAIN EWOULDBLOCK
@ -103,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
@ -435,9 +437,10 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents)
* +------+----------+----------+
*/
int offset = 0;
int offset = 1;
int need_query = 0;
char atyp = server->buf[offset++];
char atyp = server->buf[0] & 0x0F;
char atyp_btc = (server->buf[0] & 0x10) == 0x10 ? 1 : 0;
char host[256] = { 0 };
uint16_t port = 0;
struct addrinfo info;
@ -546,6 +549,58 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents)
LOGI("connect to: %s:%d", host, ntohs(port));
}
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:
* +-----------+-----------+----------+
* | Signature | Timestamp | Address |
* +-----------+-----------+----------+
* | 65 | 4 | String |
* +-----------+-----------+----------+
*/
char *signature = server->buf + offset;
uint8_t *t = (uint8_t *)server->buf + offset + 65;
uint32_t ts = ((uint32_t)*(t+0) << 24) + ((uint32_t)*(t+1) << 16)
+ ((uint32_t)*(t+2) << 8) + ((uint32_t)*(t+3) << 0);
char *address = server->buf + offset + 65 + 4;
int64_t ts_offset = (int64_t)time(NULL) - (int64_t)ts;
if (labs(ts_offset) > 60 * 30) {
if (verbose) {
LOGE("invalid timestamp: %u, offset too large: %d",
ts, (int32_t)ts_offset);
}
close_and_free_server(EV_A_ server);
return;
}
if (!bitcoin_verify_message(address, (uint8_t *)signature, t, 4)) {
if (verbose) {
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;
}
offset += 65 + 4 + strlen(address) + 1;
if (verbose) {
LOGI("bitcoin address: %s, time offset: %d",
address, (int32_t)ts_offset);
}
}
// XXX: should handle buffer carefully
if (r > offset) {
server->buf_len = r - offset;
@ -1086,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;
@ -1104,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':

15
src/utils.c

@ -266,6 +266,21 @@ void usage()
printf(
" only available in local and server mode\n");
printf("\n");
printf(
" [--bitcoin-list <bitcoin_file>] config file of address list\n");
printf(
" only available in server mode\n");
printf("\n");
printf(
" [--bitcoin-adddress <address>] config file of bitcoin address\n");
printf(
" only available in local mode\n");
printf("\n");
printf(
" [--bitcoin-privkey <private_key>] 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");

Loading…
Cancel
Save