SOCKS5 basic auth

This commit is contained in:
M66B 2016-07-28 23:27:13 +02:00
parent 1205e105e9
commit e1ed149871
7 changed files with 117 additions and 16 deletions

View File

@ -229,6 +229,8 @@ public class ActivitySettings extends AppCompatActivity implements SharedPrefere
// SOCKS5 parameters
screen.findPreference("socks5_addr").setTitle(getString(R.string.setting_socks5_addr, prefs.getString("socks5_addr", "-")));
screen.findPreference("socks5_port").setTitle(getString(R.string.setting_socks5_port, prefs.getString("socks5_port", "-")));
screen.findPreference("socks5_username").setTitle(getString(R.string.setting_socks5_username, prefs.getString("socks5_username", "-")));
screen.findPreference("socks5_password").setTitle(getString(R.string.setting_socks5_password, TextUtils.isEmpty(prefs.getString("socks5_username", "")) ? "-" : "*****"));
// PCAP parameters
screen.findPreference("pcap_record_size").setTitle(getString(R.string.setting_pcap_record_size, prefs.getString("pcap_record_size", "64")));
@ -641,7 +643,10 @@ public class ActivitySettings extends AppCompatActivity implements SharedPrefere
getPreferenceScreen().findPreference(name).setTitle(
getString(R.string.setting_dns, prefs.getString("dns", Util.getDefaultDNS(this).get(0))));
} else if ("socks5_addr".equals(name)) {
} else if ("socks5_enabled".equals(name))
ServiceSinkhole.reload("changed " + name, this);
else if ("socks5_addr".equals(name)) {
String socks5 = prefs.getString("socks5_addr", null);
try {
checkAddress(socks5);
@ -659,6 +664,14 @@ public class ActivitySettings extends AppCompatActivity implements SharedPrefere
getPreferenceScreen().findPreference(name).setTitle(getString(R.string.setting_socks5_port, prefs.getString(name, "-")));
ServiceSinkhole.reload("changed " + name, this);
} else if ("socks5_username".equals(name)) {
getPreferenceScreen().findPreference(name).setTitle(getString(R.string.setting_socks5_username, prefs.getString(name, "-")));
ServiceSinkhole.reload("changed " + name, this);
} else if ("socks5_password".equals(name)) {
getPreferenceScreen().findPreference(name).setTitle(getString(R.string.setting_socks5_password, TextUtils.isEmpty(prefs.getString(name, "")) ? "-" : "*****"));
ServiceSinkhole.reload("changed " + name, this);
} else if ("pcap_record_size".equals(name) || "pcap_file_size".equals(name)) {
if ("pcap_record_size".equals(name))
getPreferenceScreen().findPreference(name).setTitle(getString(R.string.setting_pcap_record_size, prefs.getString(name, "64")));

View File

@ -183,7 +183,7 @@ public class ServiceSinkhole extends VpnService implements SharedPreferences.OnS
private static native void jni_pcap(String name, int record_size, int file_size);
private native void jni_socks5(String ip, int port);
private native void jni_socks5(String addr, int port, String username, String password);
private native void jni_done();
@ -1115,7 +1115,14 @@ public class ServiceSinkhole extends VpnService implements SharedPreferences.OnS
if (log || log_app || filter) {
int prio = Integer.parseInt(prefs.getString("loglevel", Integer.toString(Log.WARN)));
jni_socks5(prefs.getString("socks5_addr", ""), Integer.parseInt(prefs.getString("socks5_port", "0")));
if (prefs.getBoolean("socks5_enabled", false))
jni_socks5(
prefs.getString("socks5_addr", ""),
Integer.parseInt(prefs.getString("socks5_port", "0")),
prefs.getString("socks5_username", ""),
prefs.getString("socks5_password", ""));
else
jni_socks5("", 0, "", "");
jni_start(vpn.getFd(), mapForward.containsKey(53), prio);
}
}

View File

@ -30,6 +30,8 @@ pthread_t thread_id = 0;
pthread_mutex_t lock;
char socks5_addr[INET6_ADDRSTRLEN + 1];
int socks5_port = 0;
char socks5_username[127 + 1];
char socks5_password[127 + 1];
int loglevel = ANDROID_LOG_WARN;
extern int max_tun_msg;
@ -107,6 +109,8 @@ Java_eu_faircode_netguard_ServiceSinkhole_jni_1init(JNIEnv *env, jobject instanc
*socks5_addr = 0;
socks5_port = 0;
*socks5_username = 0;
*socks5_password = 0;
pcap_file = NULL;
if (pthread_mutex_init(&lock, NULL))
@ -299,20 +303,24 @@ Java_eu_faircode_netguard_ServiceSinkhole_jni_1pcap(
}
JNIEXPORT void JNICALL
Java_eu_faircode_netguard_ServiceSinkhole_jni_1socks5(JNIEnv *env,
jobject instance, jstring ip_, jint port) {
if (ip_ == NULL || port == 0) {
*socks5_addr = 0;
socks5_port = 0;
} else {
const char *ip = (*env)->GetStringUTFChars(env, ip_, 0);
strcpy(socks5_addr, ip);
socks5_port = port;
Java_eu_faircode_netguard_ServiceSinkhole_jni_1socks5(JNIEnv *env, jobject instance, jstring addr_,
jint port, jstring username_,
jstring password_) {
const char *addr = (*env)->GetStringUTFChars(env, addr_, 0);
const char *username = (*env)->GetStringUTFChars(env, username_, 0);
const char *password = (*env)->GetStringUTFChars(env, password_, 0);
log_android(ANDROID_LOG_WARN, "SOCKS5 %s:%d", socks5_addr, socks5_port);
strcpy(socks5_addr, addr);
socks5_port = port;
strcpy(socks5_username, username);
strcpy(socks5_password, password);
(*env)->ReleaseStringUTFChars(env, ip_, ip);
}
log_android(ANDROID_LOG_WARN, "SOCKS5 %s:%d user=%s",
socks5_addr, socks5_port, socks5_username);
(*env)->ReleaseStringUTFChars(env, addr_, addr);
(*env)->ReleaseStringUTFChars(env, username_, username);
(*env)->ReleaseStringUTFChars(env, password_, password);
}
JNIEXPORT void JNICALL

View File

@ -22,6 +22,8 @@
extern struct ng_session *ng_session;
extern char socks5_addr[INET6_ADDRSTRLEN + 1];
extern int socks5_port;
extern char socks5_username[127 + 1];
extern char socks5_password[127 + 1];
extern FILE *pcap_file;
@ -267,6 +269,7 @@ void check_tcp_socket(const struct arguments *args,
if (ev->events & EPOLLOUT) {
log_android(ANDROID_LOG_INFO, "%s connected", session);
// http://www.rfc-base.org/txt/rfc-1928.txt
// https://en.wikipedia.org/wiki/SOCKS#SOCKS5
if (*socks5_addr && socks5_port)
s->tcp.socks5 = SOCKS5_HELLO;
@ -291,12 +294,27 @@ void check_tcp_socket(const struct arguments *args,
bytes == 2 && buffer[0] == 5) {
if (buffer[1] == 0)
s->tcp.socks5 = SOCKS5_CONNECT;
else if (buffer[1] == 2)
s->tcp.socks5 = SOCKS5_AUTH;
else {
s->tcp.socks5 = 0;
log_android(ANDROID_LOG_ERROR, "%s SOCKS5 auth %d not supported",
session, buffer[1]);
write_rst(args, &s->tcp);
}
} else if (s->tcp.socks5 == SOCKS5_AUTH &&
bytes == 2 && buffer[0] == 1) {
if (buffer[1] == 0) {
s->tcp.socks5 = SOCKS5_CONNECT;
log_android(ANDROID_LOG_WARN, "%s SOCKS5 auth OK", session);
} else {
s->tcp.socks5 = 0;
log_android(ANDROID_LOG_ERROR, "%s SOCKS5 auth error %d",
session, buffer[1]);
write_rst(args, &s->tcp);
}
} else if (s->tcp.socks5 == SOCKS5_CONNECT &&
bytes == 6 + (s->tcp.version == 4 ? 4 : 16) &&
buffer[0] == 5) {
@ -304,6 +322,7 @@ void check_tcp_socket(const struct arguments *args,
s->tcp.socks5 = SOCKS5_CONNECTED;
log_android(ANDROID_LOG_WARN, "%s SOCKS5 connected", session);
} else {
s->tcp.socks5 = 0;
log_android(ANDROID_LOG_ERROR, "%s SOCKS5 connect error %d",
session, buffer[1]);
write_rst(args, &s->tcp);
@ -321,6 +340,7 @@ void check_tcp_socket(const struct arguments *args,
}
} else {
s->tcp.socks5 = 0;
log_android(ANDROID_LOG_ERROR, "%s recv SOCKS5 state %d",
session, s->tcp.socks5);
write_rst(args, &s->tcp);
@ -330,7 +350,7 @@ void check_tcp_socket(const struct arguments *args,
}
if (s->tcp.socks5 == SOCKS5_HELLO) {
uint8_t buffer[3] = {5, 1, 0};
uint8_t buffer[4] = {5, 2, 0, 2};
char *h = hex(buffer, sizeof(buffer));
log_android(ANDROID_LOG_INFO, "%s sending SOCKS5 hello: %s",
session, h);
@ -342,6 +362,30 @@ void check_tcp_socket(const struct arguments *args,
write_rst(args, &s->tcp);
}
} else if (s->tcp.socks5 == SOCKS5_AUTH) {
uint8_t ulen = strlen(socks5_username);
uint8_t plen = strlen(socks5_password);
uint8_t buffer[512];
*(buffer + 0) = 1; // Version
*(buffer + 1) = ulen;
memcpy(buffer + 2, socks5_username, ulen);
*(buffer + 2 + ulen) = plen;
memcpy(buffer + 2 + ulen + 1, socks5_password, plen);
size_t len = 2 + ulen + 1 + plen;
char *h = hex(buffer, len);
log_android(ANDROID_LOG_INFO, "%s sending SOCKS5 auth: %s",
session, h);
free(h);
ssize_t sent = send(s->socket, buffer, len, MSG_NOSIGNAL);
if (sent < 0) {
log_android(ANDROID_LOG_ERROR,
"%s send SOCKS5 connect error %d: %s",
session, errno, strerror(errno));
write_rst(args, &s->tcp);
}
} else if (s->tcp.socks5 == SOCKS5_CONNECT) {
uint8_t buffer[22];
*(buffer + 0) = 5; // version

View File

@ -92,8 +92,11 @@ however it is impossible to guarantee NetGuard will work correctly on every devi
<string name="setting_vpn4">VPN IPv4: %s</string>
<string name="setting_vpn6">VPN IPv6: %s</string>
<string name="setting_dns">VPN DNS: %s</string>
<string name="setting_socks5_enabled">SOCKS5 enabled</string>
<string name="setting_socks5_addr">SOCKS5 address: %s</string>
<string name="setting_socks5_port">SOCKS5 port: %s</string>
<string name="setting_socks5_username">SOCKS5 username: %s</string>
<string name="setting_socks5_password">SOCKS5 password: %s</string>
<string name="setting_pcap_record_size">PCAP record size: %s B</string>
<string name="setting_pcap_file_size">PCAP max. file size: %s MB</string>

View File

@ -186,6 +186,11 @@
android:dependency="filter"
android:inputType="text"
android:key="dns" />
<CheckBoxPreference
android:defaultValue="false"
android:dependency="filter"
android:key="socks5_enabled"
android:title="@string/setting_socks5_enabled" />
<EditTextPreference
android:dependency="filter"
android:hint="127.0.0.1"
@ -196,6 +201,14 @@
android:hint="1080"
android:inputType="text"
android:key="socks5_port" />
<EditTextPreference
android:dependency="filter"
android:inputType="text"
android:key="socks5_username" />
<EditTextPreference
android:dependency="filter"
android:inputType="text"
android:key="socks5_password" />
<EditTextPreference
android:defaultValue="64"
android:inputType="number"

View File

@ -186,6 +186,11 @@
android:dependency="filter"
android:inputType="text"
android:key="dns" />
<eu.faircode.netguard.SwitchPreference
android:defaultValue="false"
android:dependency="filter"
android:key="socks5_enabled"
android:title="@string/setting_socks5_enabled" />
<EditTextPreference
android:dependency="filter"
android:hint="127.0.0.1"
@ -196,6 +201,14 @@
android:hint="1080"
android:inputType="text"
android:key="socks5_port" />
<EditTextPreference
android:dependency="filter"
android:inputType="text"
android:key="socks5_username" />
<EditTextPreference
android:dependency="filter"
android:inputType="text"
android:key="socks5_password" />
<EditTextPreference
android:defaultValue="64"
android:inputType="number"