Monday, February 23, 2015

Creating a station and access point interface on a single wireless NIC

There are often situations where you need to create a wi-fi access point while remaining connected to an existing wi-fi network, these kinds of networks are often called wi-fi hotspots where you share your network connection by creating a new wi-fi access point.

This is relatively easy in windows where many 3rd party propriety software such as connectify exist.

In the Linux world however, even though it is very much possible and has been done before, there exists very less documentation or software packages that help you achieve that.

So this post will guide you in
  • Setting up two virtual Wifi interfaces one for station and other for ap
  • Configuring connection to an existing network
  • Creating and configuring an access point
  • Configure IP routing between the two interfaces
This post assumes you are on a Debian system.

Creating virtual interfaces



Install the iw package.

sudo apt-get install iw 

Check if your network card supports access point mode

iw list

Note that it says AP in software(virtual) interface modes, which means we are good to go.

Wiphy phy0
 Band 1:
  Capabilities: 0x116e
   HT20/HT40
   SM Power Save disabled
   RX HT20 SGI
   RX HT40 SGI
   RX STBC 1-stream
   Max AMSDU length: 3839 bytes
   DSSS/CCK HT40
  Maximum RX AMPDU length 65535 bytes (exponent: 0x003)
  Minimum RX AMPDU time spacing: 8 usec (0x06)
  HT TX/RX MCS rate indexes supported: 0-7
.....
.....
        software interface modes (can always be added):
   * AP/VLAN
   * monitor
 valid interface combinations:
   * #{ managed, P2P-client } <= 2, #{ AP, mesh point, P2P-GO } <= 2,
     total <= 2, #channels <= 1
..... 


Note down the device name, here it is 'phy0'

Before we start creating the virtual interfaces we need to take down the default interface your OS might create automatically.

Make sure you are not using the interface

ifconfig down wlan0

and then delete it

iw dev wlan0 del

Run iwconfig to find out the interface name. Usually it is wlan0.

Now to actually create the interfaces

iw phy phy0 interface add sta type station
iw phy phy0 interface add hotspot type __ap

The interfaces won't actually work because of the MAC address conflicts.
To solve that change the MAC address of one or both the interfaces.

ip link set hotspot address 22:18:ca:08:11:c8

Thats pretty much it, you now have two virtual wireless interfaces that'll work just like the normal ones. But you'll have to repeat these steps after every boot. If you don't want to do that, create a udev rule

 ACTION=="add", SUBSYSTEM=="ieee80211", KERNEL=="phy0", \
    RUN+="/sbin/iw dev wlan0 del", \
    RUN+="/sbin/iw phy %k interface add sta type station", \
    RUN+="/sbin/iw phy %k interface add hotspot type __ap", \
    RUN+="/bin/ip link set hotspot address 22:18:ca:08:11:c8"

and put them in /etc/udev/rules.d/90-wireless.rules

Connect to an existing network



Download and install the wpa_supplicant package.

sudo apt-get install wpa_supplicant

First we need to specify whether the interface connects using a static IP or a dynamic.
edit /etc/network/interfaces and setup the station interface (in our case 'sta').

sudo nano /etc/network/interfaces

How you configure the station interface depends on the network you are trying to connect to.
Don't forget to use 'wpa-conf' to point to the wpa_supplicant configuration file with the network details.
run man wpa_supplicant.conf for more details on how to setup the config file.

your interfaces file should look like this:
auto sta
iface sta inet static
        wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf
        address         10.170.80.20
        netmask         255.255.255.128
        gateway         10.170.80.2
        dns-nameservers                 202.89.66.2  202.56.230.7

make sure to remove the iface wlan0 block.

Setup a wireless access point



To configure a hotspot requires several steps:
  • Install and configure the access point daemon
  • Install and configure a DHCP server
  • Configure the wireless adapter with a static IP address
  • Configure IP routing between the wireless and Ethernet

Install and configure the access point daemon - hostapd


sudo apt-get install hostapd

Edit the hostapd configuration file
sudo nano /etc/hostapd/hostapd.conf

Add the following lines:
interface=hotspot
driver=nl80211
logger_syslog=-1
logger_syslog_level=0
logger_stdout=-1
logger_stdout_level=2
ssid=your_access_point
wpa_passphrase=fuckyeah
country_code=IN
hw_mode=g
channel=2
ctrl_interface=/var/run/hostapd
ctrl_interface_group=0
macaddr_acl=0
auth_algs=1
ignore_broadcast_ssid=0
eap_server=0
wpa=2
wpa_pairwise=TKIP CCMP
rsn_pairwise=TKIP CCMP
ieee80211d=1

To start the hostapd daemon automatically at every boot
sudo nano /etc/default/hostapd

and remove the “#” in front of DAEMON_CONF and point it to the hostapd conf file.
DAEMON_CONF="/etc/hostapd/hostapd.conf"

Install and configure a DHCP server


sudo apt-get install isc-dhcp-server

Configure the dhcp server
sudo nano /etc/dhcp/dhcpd.conf

Friday, December 27, 2013

Custom SSLSocketFactory that trusts only your Certificate.

pre { color: #ffffff; background: #6A6A6A; }
Whenever you connect to a secure website that doesn't use a CA(Certificate authority) that is a trusted 3rd party your are most likely to get

javax.net.ssl.SSLException: Not trusted server certificate exception

when connecting through a java program or an android app.

To fix this you'll have to tell your network client to trust that sites certificate. You'll find that when using Apache Http client you have to create your own custom SSLSocketFactory or set a custom sslsocket to the connection as described at developer.android.com when using HttpUrlConnection.

To save yourself all that trouble you can use my already created custom SSLSocketFactory which works with both Apache Http Client and HttpUrlconnection.

https://gist.github.com/Shalzz/8125772

To actually use it you'll need to write a few lines of code.

For HttpURLConnection


MySSLSocketFactory sslf = null;
        try {
         KeyStore ks = MySSLSocketFactory.getKeystoreOfCA(this.getResources().openRawResource(R.raw.myCert));
         sslf = new MySSLSocketFactory(ks);
 }
        catch (Exception e) {
  e.printStackTrace();
 }
        finally {
  sslf.fixHttpsURLConnection();
 } 

Here we create a Keystore containing our certificate, in this case 'myCert'. Which we then use to get an instance of MySSLSocketFactory and then call its non static fixHttpsURLConnection() method. This sets the SSLSocketFactory created as the default SSLSocketFactory for HttpURLConnection.


For Apache Http Client

MySSLSocketFactory sslf = null;
DefaultHttpClient client  = null ;
           try {
         KeyStore ks = MySSLSocketFactory.getKeystoreOfCA(this.getResources().openRawResource(R.raw.myCert));
         client  = MySSLSocketFactory.getNewHttpClient(ks);
    }
           catch (Exception e) {
   e.printStackTrace();
    }


In this case we get the DefaultHttpClient created with KeyStore containing our Certificates.