I am trying build a VPN client mobile for Android based applications that connect to virtual infrastructure over VPN tunnel. I have a similar application for Linux/Windows and I know how to open a tun/tap device (open /dev/net/tun). How do we do the same for Android using C ?
Also what does the class VpnService in the android.net API do exactly ?
If you still wants to open a tunnel on android - native C, I suggest to take a look how android itself open it (from file: services/jni/com_android_server_connectivity_Vpn.cpp)
static int create_interface(int mtu)
{
int tun = open("/dev/tun", O_RDWR | O_NONBLOCK);
ifreq ifr4;
memset(&ifr4, 0, sizeof(ifr4));
// Allocate interface.
ifr4.ifr_flags = IFF_TUN | IFF_NO_PI;
if (ioctl(tun, TUNSETIFF, &ifr4)) {
ALOGE("Cannot allocate TUN: %s", strerror(errno));
goto error;
}
// Activate interface.
ifr4.ifr_flags = IFF_UP;
if (ioctl(inet4, SIOCSIFFLAGS, &ifr4)) {
ALOGE("Cannot activate %s: %s", ifr4.ifr_name, strerror(errno));
goto error;
}
// Set MTU if it is specified.
ifr4.ifr_mtu = mtu;
if (mtu > 0 && ioctl(inet4, SIOCSIFMTU, &ifr4)) {
ALOGE("Cannot set MTU on %s: %s", ifr4.ifr_name, strerror(errno));
goto error;
}
return tun;
error:
close(tun);
return SYSTEM_ERROR;
}
The VpnService class does exactly what you need. It provides an access to the tun device. You cannot directly open /dev/net/tun without having root rights. See the ToyVPN example project or an open source VPN project like OpenVPN for Android.
You need to be root to open tuntap on Android.
this->_handle = open("/dev/tun", O_RDWR | O_NONBLOCK | O_CLOEXEC);
if (this->_handle < 0) {
this->_handle = open("/dev/net/tun", O_RDWR | O_NONBLOCK | O_CLOEXEC);
}
For details:
https://android.googlesource.com/platform/frameworks/base.git/+/android-4.3_r2.1/services/jni/com_android_server_connectivity_Vpn.cpp
Supplement:
/dev/tun and /dev/net/tun both require an attempt to open the device. There are too many distributions of Android, each with individual changes, and tuntap devices are also slightly different.
Native-code may not be a good idea to open a tuntap!
Related
I'm having a CGI script in C language, which open the serial port ttyUSB0 in my Raspberry pi, send a data at my device and get it response.
This script perform correctly when i'm launch it manually in the terminal but my web page can't access to this port to open it.
My code :
int main (void) {
printf("Content-type: text/html\n\n");
const int fd = open ("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_SYNC);
if (fd == -1)
{
printf ("error %d opening %s: %s", errno, "ttyUSB0", strerror (errno));
return 0;
}
And the response in the web page : "error 13 opening ttyUSB0: Permission denied"
And below the output of the command "id -Gn pi" :
pi adm tty uucp dialout cdrom sudo audio video plugdev games users input netdev spi i2c gpio lpadmin
Thanks.
The command below solved my problem :
sudo adduser www-data dialout
My indent to create reverse ssh tunnel/ssh port forwarding mechanism.
Here is the actual reverse ssh command :
ssh -fN -R 101:localhost:22 computer#123.123.0.27 -p 2320
I need to run this command from my C api using popen(), i was implemented like as follows.
Note: system's public & private keys are already shared i.e, no need to give the password.
int create_tunnel (void)
{
FILE *fptr_ssh = NULL;
char sshcmd[100] = {0};
char response[100] = {0};
sprintf(sshcmd, "ssh -fN -R 101:localhost:22 computer#123.123.0.27 -p 2320");
fptr_ssh = popen(sshcmd, "r"); /* Executing ssh */
if(NULL == fptr_ssh) {
perror("popen failed");
return -1;
}
/* Getting message from fp */
if(!fgets(response, (sizeof(response)-1), fptr_ssh)) {
perror("fgets failed");
return -1;
}
printf("Msg: %s\n", response);
pclose(fptr_ssh);
return 0;
}
Success Case: if every thing fine, port forwarding will success no problem.
In Failure Case : Consider this example:
if no connectivity following message will displays in stdout (terminal).
ssh: connect to host 123.123.0.27 port 2320: Network is unreachable
but i unable to get any information from my C api /fgets() from file pointer fptr_ssh.
It return success and no message from fgets.
fgets failed: Success
I have the problem that I registered IIO events for rising and falling thresholds.
I can see the sysfs files in events subfolder and can read them, but when I try to write a new threshold it says "permission denied".
following setup:
static const struct iio_event_spec as6200_events[] = {
{
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_RISING,
.mask_separate = BIT(IIO_EV_INFO_VALUE),
}, {
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_FALLING,
.mask_separate = BIT(IIO_EV_INFO_VALUE),
}
};
static const struct iio_chan_spec as6200_channels[] = {
{
.type = IIO_TEMP,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_PROCESSED) |
BIT(IIO_CHAN_INFO_SCALE),
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ),
.event_spec = as6200_events,
.num_event_specs = ARRAY_SIZE(as6200_events),
}
};
finding: it works when I change the permissions of the in_temp_thresh_rising_value file to 666 via sudo. But why is it not created with this permissions via IIO subsystem?
This is common practice for sysfs files, as writing to those files can alter system's behavior and even compromise or break the system. So if you want to write to those files, you should do that from root, or add your user to corresponding group, or change that file mode (by udev rule or by hand).
Here is how it's done in IIO code:
IIO sysfs node names are derived from next tables in drivers/iio/industrialio-event.c: iio_ev_type_text, iio_ev_dir_text and iio_ev_info_text
node creation path is next: iio_device_add_event() -> __iio_add_chan_devattr() -> __iio_device_attr_init()
file mode for sysfs node is being set in __iio_device_attr_init():
for reading: dev_attr->attr.mode |= S_IRUGO;
so every user can read the node (because S_IRUGO allows Reading for User, Group and Others)
for writing: dev_attr->attr.mode |= S_IWUSR;
so it only can be written by root (because S_IWUSR allows writing only for file owner, which is root)
Another solution to this problem is to use a combination of libiio's network and local contexts. In this case, a libiio daemon would be started with the appropriate privileges to write to the sysfs files, and the user application would then connect with this daemon using a libiio network context.
I hooked native api ZwCreateFile, and wdk doc says windows use ZwCreateFile to create or open a directory. I can detect the operation of opening testdir, but i failed to stop the open directory operation.
My code of my own FakeZwCreateFile like this:
NTSTATUS FakeZwOpenFile(
OUT PHANDLE FileHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN ULONG ShareAccess,
IN ULONG OpenOptions
)
{
NTSTATUS rtStatus = STATUS_SUCCESS;
UNICODE_STRING test = RTL_CONSTANT_STRING(L"\\??\\c:\\testdir");
if (!RtlCompareUnicodeString(ObjectAttributes->ObjectName, &test, TRUE))
{
DbgPrint("%wZ\n", &test);
FileHandle = NULL;
IoStatusBlock->Status = rtStatus = STATUS_ACCESS_DENIED;
goto exit;
}
Orig:
OrigZwOpenFile = (NTOPENFILE)oldServiceAddr[SYSTEM_INDEX(ZwOpenFile)];
rtStatus = OrigZwOpenFile(
FileHandle,
DesiredAccess,
ObjectAttributes,
IoStatusBlock,
ShareAccess,
OpenOptions
);
exit:
return rtStatus;
}
Why i failed to stop opening the c:\testdir directory?? And what shoud i do to intercept the operations of creating new folders????
In this case is better to use File System Filter Drivers instead of SSDT hooking, Because FS Filter Drivers work correctly in 64Bit version of windows but SSDT only can use in 32Bit (If you can bypass windows Patch Guard then you can use SSDT hook in 32Bit) !
The CM108 from C-Media has 4 GPIO pin that you can access via a hid interface.
Using the generic write function in Windows I was able to write to the gpio pins.
However I'm trying to do the same thing in Linux without success.
The linux kernel detect the device as a hidraw device.
Note: I was able to read from the device, just not write. (I've run the app as root just to make sure it wasn't a permission issue).
I got this working, here's how.
I needed to create a new linux hid kernel mod. (it wasn't that hard)/*
/*
* Driver for the C-Media 108 chips
*
* Copyright (C) 2009 Steve Beaulac <steve#sagacity.ca>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 2.
*/
/*
* This driver is based on the cm109.c driver
*/
#include <linux/device.h>
#include <linux/hid.h>
#include <linux/module.h>
#define DRIVER_VERSION "20090526"
#define DRIVER_AUTHOR "Steve Beaulac"
#define DRIVER_DESC "C-Media 108 chip"
#define CM108_VENDOR_ID 0x0d8c
#define CM108_PRODUCT_ID 0x000c
#ifdef CONFIG_USB_DYNAMIC_MINORS
#define CM108_MINOR_BASE 0
#else
#define CM108_MINOR_BASE 96
#endif
/*
* Linux interface and usb initialisation
*/
static int cm108_hid_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
int ret;
ret = hid_parse(hdev);
if (ret) {
dev_err(&hdev->dev, "parse failed\n");
goto error;
}
ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
if (ret) {
dev_err(&hdev->dev, "hw start failed\n");
goto error;
}
return 0;
error:
return ret;
}
static struct hid_device_id cm108_device_table[] = {
{ HID_USB_DEVICE (CM108_VENDOR_ID, CM108_PRODUCT_ID) },
/* you can add more devices here with product ID 0x0008 - 0x000f */
{ }
};
MODULE_DEVICE_TABLE (hid, cm108_device_table);
static struct hid_driver hid_cm108_driver = {
.name = "cm108",
.id_table = cm108_device_table,
.probe = cm108_hid_probe,
};
static int hid_cm108_init(void)
{
return hid_register_driver(&hid_cm108_driver);
}
static void hid_cm108_exit(void)
{
hid_unregister_driver(&hid_cm108_driver);
}
module_init(hid_cm108_init);
module_exit(hid_cm108_exit);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
used This makefile
obj-m += cm108.o
and compile the module
make -C /lib/modules/`uname -r`/build/ M=`pwd` EXTRAVERSION="-generic" modules
sudo make -C /lib/modules/`uname -r`/build/ M=`pwd` EXTRAVERSION="-generic" modules_install
depmod -a
I had to modify the modules.order file so that my module would get queried before the generic hid linux module.
This modules make sure that the hidraw uses Interface 2.
Then I can use fopen to read and write to the GPIO pin of the CM108 chip.
BTW: when writing you need to write 5byte the 1st byte is used for the HID_OUTPUT_REPORT
Most hardware in Linux is accessible as a file. If the driver created a hardware node for it on the file-system, you're in luck. You will be able to write to it using regular file routines. Otherwise, you may need to do some assembly magic, which may require you to write a kernel module to do it.
Here is a complete example of how to write to the CM108/CM119 GPIO pins on Linux.
https://github.com/wb2osz/direwolf/blob/dev/cm108.c
You don't need to run as root or write your own device driver.
I have the opposite problem. I'm trying to figure out how to do the same thing on Windows.