Native quick restart, allow root, terminate not allowed session on start

This commit is contained in:
M66B 2016-01-24 07:47:32 +01:00
parent 8475dbdf9d
commit 1e75535836
5 changed files with 97 additions and 31 deletions

View File

@ -362,10 +362,15 @@ public class ActivitySettings extends AppCompatActivity implements SharedPrefere
prefs.edit().putBoolean("show_system", manage).apply();
SinkholeService.reload(null, "setting changed", this);
} else if ("tethering".equals(name))
SinkholeService.reload(null, "setting changed", this);
} else if ("tethering".equals(name)) {
if (prefs.getBoolean("filter", false)) {
// Requires a full stop to reconfigure the VPN
SinkholeService.stop("tethering", this);
SinkholeService.start("tethering", this);
} else
SinkholeService.reload(null, "setting changed", this);
else if ("log".equals(name)) {
} else if ("log".equals(name)) {
if (prefs.getBoolean(name, false) && !IAB.isPurchased(ActivityPro.SKU_LOG, this)) {
prefs.edit().putBoolean(name, false).apply();
((SwitchPreference) getPreferenceScreen().findPreference(name)).setChecked(false);

View File

@ -39,7 +39,7 @@ import java.util.ArrayList;
import java.util.List;
public class IAB implements ServiceConnection {
private static final String TAG = "Netguard.IAB";
private static final String TAG = "NetGuard.IAB";
private Context context;
private Delegate delegate;

View File

@ -325,7 +325,7 @@ public class SinkholeService extends VpnService implements SharedPreferences.OnS
if (vpn == null)
throw new IllegalStateException("VPN start failed");
startNative(listAllowed);
startNative(vpn, listAllowed);
removeWarningNotifications();
updateEnforcingNotification(listAllowed.size(), listRule.size());
@ -333,6 +333,8 @@ public class SinkholeService extends VpnService implements SharedPreferences.OnS
}
private void reload() {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(SinkholeService.this);
if (state != State.enforcing) {
if (state != State.none) {
Log.d(TAG, "Stop foreground state=" + state.toString());
@ -343,28 +345,44 @@ public class SinkholeService extends VpnService implements SharedPreferences.OnS
Log.d(TAG, "Start foreground state=" + state.toString());
}
// Seamless handover
ParcelFileDescriptor prev = vpn;
List<Rule> listRule = Rule.getRules(true, TAG, SinkholeService.this);
List<Rule> listAllowed = getAllowedRules(listRule);
vpn = startVPN(listAllowed);
if (prev != null && vpn == null) {
Log.w(TAG, "Handover failed");
stopVPN(prev);
prev = null;
vpn = startVPN(listAllowed);
if (prefs.getBoolean("filter", false)) {
Log.i(TAG, "Native restart");
if (vpn != null)
jni_stop(vpn.getFd(), false);
if (vpn == null)
throw new IllegalStateException("Handover failed");
vpn = startVPN(listAllowed);
if (vpn == null)
throw new IllegalStateException("VPN start failed");
startNative(vpn, listAllowed);
} else {
Log.i(TAG, "VPN restart");
// Attempt seamless handover
ParcelFileDescriptor prev = vpn;
vpn = startVPN(listAllowed);
if (prev != null && vpn == null) {
Log.w(TAG, "Handover failed");
stopVPN(prev);
prev = null;
vpn = startVPN(listAllowed);
if (vpn == null)
throw new IllegalStateException("Handover failed");
}
if (prev != null) {
jni_stop(prev.getFd(), false);
stopVPN(prev);
}
startNative(vpn, listAllowed);
}
// TODO drain old VPN
jni_stop(vpn.getFd(), false);
startNative(listAllowed);
if (prev != null)
stopVPN(prev);
updateEnforcingNotification(listAllowed.size(), listRule.size());
}
@ -701,7 +719,7 @@ public class SinkholeService extends VpnService implements SharedPreferences.OnS
}
}
private void startNative(List<Rule> listAllowed) {
private void startNative(ParcelFileDescriptor vpn, List<Rule> listAllowed) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(SinkholeService.this);
boolean log = prefs.getBoolean("log", false);
boolean filter = prefs.getBoolean("filter", false);
@ -779,9 +797,10 @@ public class SinkholeService extends VpnService implements SharedPreferences.OnS
}
private int[] getAllowedUids(List<Rule> listAllowed) {
int[] uid = new int[listAllowed.size()];
int[] uid = new int[listAllowed.size() + 1];
uid[0] = 0; // Allow root (DNS, etc)
for (int i = 0; i < listAllowed.size(); i++)
uid[i] = listAllowed.get(i).info.applicationInfo.uid;
uid[i + 1] = listAllowed.get(i).info.applicationInfo.uid;
return uid;
}

View File

@ -150,6 +150,9 @@ Java_eu_faircode_netguard_SinkholeService_jni_1start(
for (int i = 0; i < args->ucount; i++)
log_android(ANDROID_LOG_DEBUG, "Allowed uid %d", args->uids[i]);
// Terminate sessions not allowed anymore
check_allowed(args);
// Start native thread
int err = pthread_create(&thread_id, NULL, handle_events, (void *) args);
if (err == 0)
@ -222,6 +225,38 @@ Java_eu_faircode_netguard_SinkholeService_jni_1pcap(JNIEnv *env, jclass type, js
// Private functions
void check_allowed(const struct arguments *args) {
struct udp_session *u = udp_session;
while (u != NULL) {
int found = 0;
for (int i = 0; i < args->ucount; i++)
if (u->uid == args->uids[i]) {
found = 1;
break;
}
if (!found) {
u->error = 1;
log_android(ANDROID_LOG_WARN, "UDP terminate uid %d", u->uid);
}
u = u->next;
}
struct tcp_session *t = tcp_session;
while (t != NULL) {
int found = 0;
for (int i = 0; i < args->ucount; i++)
if (t->uid == args->uids[i]) {
found = 1;
break;
}
if (!found) {
t->state = TCP_TIME_WAIT;
log_android(ANDROID_LOG_WARN, "TCP terminate uid %d", t->uid);
}
t = t->next;
}
}
void clear_sessions() {
struct udp_session *u = udp_session;
while (u != NULL) {
@ -300,14 +335,15 @@ void *handle_events(void *a) {
if (ready < 0) {
if (errno == EINTR) {
if (stopping && signaled) { ;
log_android(ANDROID_LOG_WARN, "pselect signaled");
log_android(ANDROID_LOG_WARN, "pselect signaled tun %d", args->tun);
break;
} else {
log_android(ANDROID_LOG_DEBUG, "pselect interrupted");
log_android(ANDROID_LOG_DEBUG, "pselect interrupted %d", args->tun);
continue;
}
} else {
log_android(ANDROID_LOG_ERROR, "pselect error %d: %s", errno, strerror(errno));
log_android(ANDROID_LOG_ERROR, "pselect tun %d error %d: %s",
args->tun, errno, strerror(errno));
break;
}
}
@ -389,7 +425,7 @@ void *handle_events(void *a) {
return NULL;
}
void report_exit(struct arguments *args) {
void report_exit(const struct arguments *args) {
jclass cls = (*args->env)->GetObjectClass(args->env, args->instance);
jmethodID mid = jniGetMethodID(args->env, cls, "selectExit", "(Z)V");
@ -411,7 +447,8 @@ void check_sessions(const struct arguments *args) {
log_android(ANDROID_LOG_WARN, "UDP timeout");
if (close(u->socket))
log_android(ANDROID_LOG_ERROR, "UDP close error %d: %s", errno, strerror(errno));
log_android(ANDROID_LOG_ERROR, "UDP close %d error %d: %s",
u->socket, errno, strerror(errno));
if (ul == NULL)
udp_session = u->next;
@ -459,7 +496,8 @@ void check_sessions(const struct arguments *args) {
source, ntohs(t->source), dest, ntohs(t->dest), t->socket);
if (close(t->socket))
log_android(ANDROID_LOG_ERROR, "close error %d: %s", errno, strerror(errno));
log_android(ANDROID_LOG_ERROR, "close %d error %d: %s",
t->socket, errno, strerror(errno));
t->time = time(NULL);
t->state = TCP_CLOSE;
@ -988,6 +1026,8 @@ jboolean handle_udp(const struct arguments *args, const uint8_t *buffer, size_t
if (check_dns(args, cur, buffer, length))
return 0;
// TODO check DHCP (tethering)
log_android(ANDROID_LOG_INFO, "UDP forward from tun %s/%u to %s/%u data %d",
source, ntohs(udphdr->source), dest, ntohs(udphdr->dest), datalen);

View File

@ -123,13 +123,15 @@ typedef struct __attribute__((__packed__)) dns_response {
#define DNS_TTL 3600 // seconds
void check_allowed(const struct arguments *args);
void clear_sessions();
void handle_signal(int sig, siginfo_t *info, void *context);
void *handle_events(void *a);
void report_exit(struct arguments *args);
void report_exit(const struct arguments *args);
void check_sessions(const struct arguments *args);