mirror of
https://github.com/transmission/transmission
synced 2024-12-26 01:27:28 +00:00
RPC ACL: (1) add a new call for testing ACLs (2) add wildcard notation support (3) add regression tests for the ACL tester and wildcard handler
This commit is contained in:
parent
a3324fbeea
commit
c724a73fb4
6 changed files with 195 additions and 16 deletions
|
@ -91,6 +91,7 @@ TESTS = \
|
|||
bencode-test \
|
||||
clients-test \
|
||||
json-test \
|
||||
rpc-test \
|
||||
test-fastset \
|
||||
test-peer-id \
|
||||
utils-test
|
||||
|
@ -117,6 +118,8 @@ clients_test_SOURCES = clients-test.c
|
|||
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
|
||||
|
|
|
@ -11,6 +11,9 @@
|
|||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h> /* isdigit */
|
||||
#include <errno.h>
|
||||
#include <stdlib.h> /* strtol */
|
||||
#include <string.h>
|
||||
|
||||
#include <libevent/event.h>
|
||||
|
@ -218,13 +221,61 @@ testACL( const char * s )
|
|||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
tr_rpcSetACL( tr_rpc_server * server, const char * acl, char ** setme_errmsg )
|
||||
/* 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 )
|
||||
{
|
||||
const int isRunning = server->ctx != NULL;
|
||||
int ret = 0;
|
||||
char * errmsg = testACL( acl );
|
||||
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_rpcTestACL( const tr_rpc_server * server UNUSED,
|
||||
const char * acl,
|
||||
char ** setme_errmsg )
|
||||
{
|
||||
int ret = 0;
|
||||
char * cidr = cidrize( acl );
|
||||
char * errmsg = testACL( cidr );
|
||||
if( errmsg )
|
||||
{
|
||||
if( setme_errmsg )
|
||||
|
@ -233,13 +284,27 @@ tr_rpcSetACL( tr_rpc_server * server, const char * acl, char ** 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 );
|
||||
|
|
|
@ -32,6 +32,10 @@ void tr_rpcSetPort ( tr_rpc_server * 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 );
|
||||
|
|
75
libtransmission/rpc-test.c
Normal file
75
libtransmission/rpc-test.c
Normal file
|
@ -0,0 +1,75 @@
|
|||
#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;
|
||||
}
|
|
@ -775,6 +775,14 @@ tr_sessionSetRPCCallback( tr_handle * session,
|
|||
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,
|
||||
|
|
|
@ -292,21 +292,45 @@ void tr_sessionSetRPCPort( tr_handle *, int port );
|
|||
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.
|
||||
* @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>.
|
||||
*
|
||||
* The default string is "+127.0.0.1"
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
|
|
Loading…
Reference in a new issue