bencode-test \
clients-test \
json-test \
+ rpc-test \
test-fastset \
test-peer-id \
utils-test
clients_test_LDADD = $(APPS_LDADD)
json_test_SOURCES = json-test.c
json_test_LDADD = $(APPS_LDADD)
+rpc_test_SOURCES = rpc-test.c
+rpc_test_LDADD = $(APPS_LDADD)
test_fastset_SOURCES = test-fastset.c
test_fastset_LDADD = $(APPS_LDADD)
test_peer_id_SOURCES = test-peer-id.c
*/
#include <assert.h>
+#include <ctype.h> /* isdigit */
+#include <errno.h>
+#include <stdlib.h> /* strtol */
#include <string.h>
#include <libevent/event.h>
return NULL;
}
+/* 192.*.*.* --> 192.0.0.0/8
+ 192.64.*.* --> 192.64.0.0/16
+ 192.64.1.* --> 192.64.1.0/24
+ 192.64.1.2 --> 192.64.1.2/32 */
+static void
+cidrizeOne( const char * in, int len, struct evbuffer * out )
+{
+ int stars = 0;
+ const char * pch;
+ const char * end;
+ char zero = '0';
+ char huh = '?';
+
+ for( pch=in, end=pch+len; pch!=end; ++pch ) {
+ if( stars && isdigit(*pch) )
+ evbuffer_add( out, &huh, 1 );
+ else if( *pch!='*' )
+ evbuffer_add( out, pch, 1 );
+ else {
+ evbuffer_add( out, &zero, 1 );
+ ++stars;
+ }
+ }
+
+ evbuffer_add_printf( out, "/%d", (32-(stars*8)));
+}
+
+char*
+cidrize( const char * acl )
+{
+ int len;
+ const char * walk = acl;
+ char * ret;
+ struct evbuffer * out = evbuffer_new( );
+
+ FOR_EACH_WORD_IN_LIST( walk, len )
+ {
+ cidrizeOne( walk, len, out );
+ evbuffer_add_printf( out, ", " );
+ }
+
+ /* the -2 is to eat the final ", " */
+ ret = tr_strndup( (char*) EVBUFFER_DATA(out), EVBUFFER_LENGTH(out)-2 );
+ evbuffer_free( out );
+ return ret;
+}
+
int
-tr_rpcSetACL( tr_rpc_server * server, const char * acl, char ** setme_errmsg )
+tr_rpcTestACL( const tr_rpc_server * server UNUSED,
+ const char * acl,
+ char ** setme_errmsg )
{
- const int isRunning = server->ctx != NULL;
int ret = 0;
- char * errmsg = testACL( acl );
-
+ char * cidr = cidrize( acl );
+ char * errmsg = testACL( cidr );
if( errmsg )
{
if( setme_errmsg )
tr_free( errmsg );
ret = -1;
}
- else
+ tr_free( cidr );
+ return ret;
+}
+
+int
+tr_rpcSetACL( tr_rpc_server * server,
+ const char * acl,
+ char ** setme_errmsg )
+{
+ char * cidr = cidrize( acl );
+ const int ret = tr_rpcTestACL( server, cidr, setme_errmsg );
+
+ if( ret )
{
+ const int isRunning = server->ctx != NULL;
+
if( isRunning )
stopServer( server );
tr_free( server->acl );
- server->acl = tr_strdup( acl );
+ server->acl = tr_strdup( cidr );
if( isRunning )
startServer( server );
int tr_rpcGetPort ( const tr_rpc_server * server );
+int tr_rpcSetTest ( const tr_rpc_server * server,
+ const char * acl,
+ char ** allocme_errmsg );
+
int tr_rpcSetACL ( tr_rpc_server * server,
const char * acl,
char ** allocme_errmsg );
--- /dev/null
+#include <stdio.h> /* fprintf */
+#include <string.h> /* strcmp */
+#include "transmission.h"
+#include "utils.h"
+
+#define VERBOSE 0
+
+int test = 0;
+
+#define check(A) { \
+ ++test; \
+ if (A) { \
+ if( VERBOSE ) \
+ fprintf( stderr, "PASS test #%d (%s, %d)\n", test, __FILE__, __LINE__ ); \
+ } else { \
+ if( VERBOSE ) \
+ fprintf( stderr, "FAIL test #%d (%s, %d)\n", test, __FILE__, __LINE__ ); \
+ return test; \
+ } \
+}
+
+extern char* cidrize( const char * in );
+
+extern int tr_rpcTestACL( const void * unused,
+ const char * acl,
+ char ** setme_errmsg );
+
+static int
+testWildcard( const char * in, const char * expected )
+{
+ int ok;
+ char * str = cidrize( in );
+/*fprintf( stderr, "in [%s] out [%s] should be [%s]\n", in, str, expected );*/
+ ok = expected ? !strcmp( expected, str ) : !str;
+ tr_free( str );
+ return ok;
+}
+
+static int
+test_acl( void )
+{
+ int err;
+ char * errmsg = NULL;
+
+ check( testWildcard( "192.*.*.*", "192.0.0.0/8" ) );
+ check( testWildcard( "192.64.*.*", "192.64.0.0/16" ) );
+ check( testWildcard( "192.64.0.*", "192.64.0.0/24" ) );
+ check( testWildcard( "192.64.0.1", "192.64.0.1/32" ) );
+ check( testWildcard( "+192.*.*.*, -192.64.*.*", "+192.0.0.0/8, -192.64.0.0/16" ) );
+
+ err = tr_rpcTestACL( NULL, "+192.*.*.*", &errmsg );
+ check( !err );
+ check( !errmsg );
+ err = tr_rpcTestACL( NULL, "+192.*.8.*", &errmsg );
+ check( err );
+ check( errmsg );
+ tr_free( errmsg );
+ errmsg = NULL;
+ err = tr_rpcTestACL( NULL, "+192.*.*.*, -192.168.*.*", &errmsg );
+ check( !err );
+ check( !errmsg );
+
+ return 0;
+}
+
+int
+main( void )
+{
+ int i;
+
+ if(( i = test_acl( )))
+ return i;
+
+ return 0;
+}
session->rpc_func_user_data = user_data;
}
+int
+tr_sessionTestRPCACL( const tr_handle * session,
+ const char * acl,
+ char ** allocme_errmsg )
+{
+ return tr_rpcTestACL( session->rpcServer, acl, allocme_errmsg );
+}
+
int
tr_sessionSetRPCACL( tr_handle * session,
const char * acl,
int tr_sessionGetRPCPort( const tr_handle * );
/**
- * Specify access control list (ACL). ACL is a comma separated list
- * of IP subnets, each subnet is prepended by a '-' or '+' sign.
- * Plus means allow, minus means deny. If the subnet mask is omitted,
- * like * "-1.2.3.4", it means a single IP address. The mask may vary
- * from 0 to 32 inclusive.
- *
- * The default string is "+127.0.0.1"
+ * @brief test an ACL's syntax without modifying the RPC settings.
+ *
+ * ACL is a comma separated list of IP subnets, each subnet is prepended
+ * by a '+' or '-' sign to denote 'allow' or 'deny'. If the subnet mask
+ * is omitted, like "-1.2.3.4", it means a single IP address. The mask
+ * may vary from 0 to 32 inclusive. A simple primer on x.x.x.x/n notation
+ * can be found at <http://25yearsofprogramming.com/blog/20070803.htm>.
*
- * @param acl the new ACL to use.
+ * Since wildcards are more familiar to most users than netmasks,
+ * libtransmission supports a wildcard notation that it
+ * converts into cidr required by the embedded http server.
+ * So, notation like "+192.168.*.*" is accepted by libtransmission and is
+ * converted to "+192.168.0.0/16" before it reaches the server.
+
+ * @param acl the ACL to test
* @param allocme_errmsg If the ACL can't be parsed, this is set to a
* newly-allocated error string describing the problem.
* The client should tr_free() this string when done.
- *
* @return 0 on success, -1 on failure due to an unparseable ACL.
+ */
+int tr_sessionTestRPCACL( const tr_handle * session,
+ const char * acl,
+ char ** allocme_errmsg );
+
+/**
+ * @brief Specify access control list (ACL).
+ ACL is a comma separated list
+ * of IP subnets, each subnet is prepended by a '-' or '+' sign.
+ * Plus means allow, minus means deny. If the subnet mask is omitted,
+ * like "-1.2.3.4", it means a single IP address. The mask may vary
+ * from 0 to 32 inclusive.
+ *
+ * http://25yearsofprogramming.com/blog/20070803.htm has a simple
+ * primer on x.x.x.x/n notation for those interested.
+ *
+ * The parameters and return value follow the same behavior as
+ * tr_sessionTestRPCACL().
*
+ * @see tr_sessionTestRPCACL
* @see tr_sessionInitFull
* @see tr_sessionGetRPCACL
*/