Perhaps not something to have default in dropbear, put perhaps of interest for someone...
In order to restrict access from certain ip addresses only, you can, with this patch, start a dropbear with option -S This will only allow password logins if a corresponding file /etc/dropbear/ip_<ipnumber>_any.allow exists. It will also check for /etc/dropbear/ip_<ipnumber>_<username>.allow for granting access to specific usernames only If you start dropbear with -S -S it will also use this restriction for pubkey validation Example: # blocking password and pubkey from unknown locations, using a valid pubkey root@core ~# ./dropbear -S -S -F -p 2022 [24472] Oct 04 12:30:21 Not backgrounding [24473] Oct 04 12:30:40 Child connection from ::ffff:192.168.1.10:49799 [24473] Oct 04 12:30:40 Exit before auth (user 'root', 0 fails): Remote address ::ffff:192.168.1.10:49799 is not allowed to connect with public key or password # blocking password from unknown locations, using a valid pubkey root@core ~# ./dropbear -S -F -p 2022 [24486] Oct 04 12:30:55 Not backgrounding [24487] Oct 04 12:31:10 Child connection from ::ffff:192.168.1.10:49801 [24487] Oct 04 12:31:11 Pubkey auth succeeded for 'root' with key md5 14:07:9a:1d:d9:64:45:db:88:d8:78:62:45:1e:88:21 from ::ffff: 192.168.1.10:49801 # blocking password from unknown locations, using a valid password root@core ~# ./dropbear -S -F -p 2022 [24551] Oct 04 12:31:25 Not backgrounding [24552] Oct 04 12:32:06 Child connection from ::ffff:192.168.1.10:49802 [24552] Oct 04 12:32:09 IP access denied : file /etc/dropbear/ip_192.168.1.10_root.allow not found [24552] Oct 04 12:32:09 IP access denied : file /etc/dropbear/ip_192.168.1.10_any.allow not found [24552] Oct 04 12:32:09 Exit before auth (user 'root', 0 fails): Remote address ::ffff:192.168.1.10:49802 is not allowed to connect with password # grant connections for root from 192.168.1.10, using a valid publickey root@core ~# touch /etc/dropbear/ip_192.168.1.10_root.allow root@core ~# ./dropbear -S -S -F -p 2022 [24578] Oct 04 12:33:02 Not backgrounding [24579] Oct 04 12:33:20 Child connection from ::ffff:192.168.1.10:49803 [24579] Oct 04 12:33:20 IP access allowed : file /etc/dropbear/ip_192.168.1.10_root.allow found [24579] Oct 04 12:33:20 Pubkey auth succeeded for 'root' with key md5 14:07:9a:1d:d9:64:45:db:88:d8:78:62:45:1e:88:21 from ::ffff: 192.168.1.10:49803 Have fun with it... Hans
--- ../dropbear-2014.65/options.h 2014-09-11 02:37:28.000000000 -0600 +++ options.h 2014-10-04 01:28:55.000000000 -0600 @@ -20,6 +20,10 @@ #endif /* Default hostkey paths - these can be specified on the command line */ +#ifndef CONFIG_DIRECTORY +#define CONFIG_DIRECTORY "/etc/dropbear" +#endif +/* Default hostkey paths - these can be specified on the command line */ #ifndef DSS_PRIV_FILENAME #define DSS_PRIV_FILENAME "/etc/dropbear/dropbear_dss_host_key" #endif --- ../dropbear-2014.65/runopts.h 2014-08-08 07:40:47.000000000 -0600 +++ runopts.h 2014-10-04 01:25:22.000000000 -0600 @@ -87,6 +87,7 @@ typedef struct svr_runopts { int norootlogin; + int restrictlogins; int noauthpass; int norootpass; int allowblankpass; --- ../dropbear-2014.65/svr-runopts.c 2014-08-08 07:40:47.000000000 -0600 +++ svr-runopts.c 2014-10-04 02:58:05.000000000 -0600 @@ -68,6 +68,7 @@ static void printhelp(const char * progn "-m Don't display the motd on login\n" #endif "-w Disallow root logins\n" + "-S Enable logins from restricted addresses\n" #if defined(ENABLE_SVR_PASSWORD_AUTH) || defined(ENABLE_SVR_PAM_AUTH) "-s Disable password logins\n" "-g Disable password logins for root\n" @@ -127,6 +128,7 @@ void svr_getopts(int argc, char ** argv) svr_opts.forkbg = 1; svr_opts.norootlogin = 0; svr_opts.noauthpass = 0; + svr_opts.restrictlogins = 0; svr_opts.norootpass = 0; svr_opts.allowblankpass = 0; svr_opts.inetdmode = 0; @@ -244,6 +246,9 @@ void svr_getopts(int argc, char ** argv) case 'I': next = &idle_timeout_arg; break; + case 'S': + svr_opts.restrictlogins++; + break; #if defined(ENABLE_SVR_PASSWORD_AUTH) || defined(ENABLE_SVR_PAM_AUTH) case 's': svr_opts.noauthpass = 1; --- ../dropbear-2014.65/svr-auth.c 2014-08-08 07:40:47.000000000 -0600 +++ svr-auth.c 2014-10-04 05:35:21.000000000 -0600 @@ -79,6 +79,46 @@ static void authclear() { } +/* check if a file ip_<ipnumber>_<user>.allow or ip_<ipnumber>.allow is found + * which determines if access is allowed or not. */ +static int restrictlogin_valid(char *usernm, int log) +{ + char address[65], *ptr, fn[256]; + + /* get remote ip:port address IPv4 or IPv6 */ + if (strncmp(svr_ses.addrstring,"::ffff:",7)==0) { + strlcpy(address,&svr_ses.addrstring[7],sizeof(address)); + } else { + strlcpy(address,svr_ses.addrstring,sizeof(address)); + } + ptr=strrchr(address,':'); + if (ptr!=0) { + /* remove the port part, leaving the ip only in the address */ + *ptr='\0'; + /* change all remaining : characters into . characters (IPv6) */ + while ( (ptr=strchr(address,':')) !=0 ) { + *ptr='.'; + } + /* test if user from ip is allowed */ + snprintf(fn,sizeof(fn),"%s/ip_%s_%s.allow",CONFIG_DIRECTORY,address,usernm); + if (access(fn,F_OK)==0) { + dropbear_log(LOG_INFO, "IP access allowed : file %s found",fn); + return(1); + } else if (log) { + dropbear_log(LOG_INFO, "IP access denied : file %s not found",fn); + } + /* test if any user from ip is allowed */ + snprintf(fn,sizeof(fn),"%s/ip_%s_any.allow",CONFIG_DIRECTORY,address); + if (access(fn,F_OK)==0) { + dropbear_log(LOG_INFO, "IP access allowed : file %s found",fn); + return(1); + } else if (log) { + dropbear_log(LOG_INFO, "IP access denied : file %s not found",fn); + } + } + return(0); +} + /* Send a banner message if specified to the client. The client might * ignore this, but possibly serves as a legal "no trespassing" sign */ void send_msg_userauth_banner(buffer *banner) { @@ -148,6 +188,10 @@ void recv_msg_userauth_request() { strncmp(methodname, AUTH_METHOD_NONE, AUTH_METHOD_NONE_LEN) == 0) { TRACE(("recv_msg_userauth_request: 'none' request")) + if (svr_opts.allowblankpass && svr_opts.restrictlogins!=0 && restrictlogin_valid(username,1)==0) { + dropbear_log(LOG_INFO, "IP access denied for blank password" ); + valid_user = 0; + } if (valid_user && svr_opts.allowblankpass && !svr_opts.noauthpass @@ -176,6 +220,13 @@ void recv_msg_userauth_request() { if (methodlen == AUTH_METHOD_PASSWORD_LEN && strncmp(methodname, AUTH_METHOD_PASSWORD, AUTH_METHOD_PASSWORD_LEN) == 0) { + if (svr_opts.restrictlogins!=0 && restrictlogin_valid(username,1)==0 ) { + /* do not allow retries */ + m_free(username); + m_free(servicename); + m_free(methodname); + dropbear_exit("Remote address %s is not allowed to connect with password",svr_ses.addrstring); + } if (valid_user) { svr_auth_password(); goto out; @@ -191,6 +242,13 @@ void recv_msg_userauth_request() { if (methodlen == AUTH_METHOD_PASSWORD_LEN && strncmp(methodname, AUTH_METHOD_PASSWORD, AUTH_METHOD_PASSWORD_LEN) == 0) { + if (valid_user && svr_opts.restrictlogins!=0 && restrictlogin_valid(username,1)==0 ) { + /* do not allow retries */ + m_free(username); + m_free(servicename); + m_free(methodname); + dropbear_exit("Remote address %s is not allowed to connect with pam password",svr_ses.addrstring); + } if (valid_user) { svr_auth_pam(); goto out; @@ -204,6 +262,13 @@ void recv_msg_userauth_request() { if (methodlen == AUTH_METHOD_PUBKEY_LEN && strncmp(methodname, AUTH_METHOD_PUBKEY, AUTH_METHOD_PUBKEY_LEN) == 0) { + if (svr_opts.restrictlogins==2 && restrictlogin_valid(username,0)==0) { + /* if pubkey is not allowed , so is password not... so break off connection */ + m_free(username); + m_free(servicename); + m_free(methodname); + dropbear_exit("Remote address %s is not allowed to connect with public key or password",svr_ses.addrstring); + } if (valid_user) { svr_auth_pubkey(); } else {