README.md

# Nerves.NetworkInterface
[![Build Status](https://travis-ci.org/nerves-project/nerves_network_interface.svg?branch=master)](https://travis-ci.org/nerves-project/nerves_network_interface)

This package enables Elixir applications to configure, get the status of,
and listen to events from LAN and WiFi network interfaces. It is not meant
as a full-featured network interface management library and lacks a majority
of the features available. However, its goal is to support the set of
networking parameters that make sense for end systems in home, office, and
industrial environments. This includes:

 * Enumerating available interfaces
 * Reporting when new interfaces appear and disappear (USB WiFi dongle insertion/removal)
 * Querying link-level interface status and statistics
 * Reporting link-level interface status changes
 * Configuring IP addresses, subnets, gateways, etc.
 * Bringing interfaces up and down

Currently only IPv4 is supported. If you use IPv6, I'd be interested in
working with you to integrate IPv6 support.

## Nerves.NetworkInterface or [Nerves.Networking](https://github.com/nerves-project/nerves_networking)?

The purpose of Nerves.NetworkInterface is to handles low level access to Linux
network interfaces. The Nerves.Networking module currently also takes care of
the low level stuff, and also of IP address assignment. The low level
functionality in Nerves.Networking should be removed in favor of
Nerves.NetworkInterface. The
[Nerves.InterimWifi](https://github.com/nerves-project/nerves_interim_wifi)
project does already make use of the functionality offered by
Nerves.NetworkInterface.

## Prerequisites

This module requires [libmnl](http://netfilter.org/projects/libmnl/) to build.
If you're running a Debian-based system, you can get it by running:

    sudo apt-get install libmnl-dev

Nerves includes `libmnl` by default.

When not crosscompiling, be aware that the Makefile runs `sudo` to set the
permissions on the `priv/netif` binary, so you'll be asked your password towards
the end. If you do not require additional privileges to modify network
interfaces on your system, you can bypass the calls to sudo by setting the
SUDO environment variable to `true`. I.e., `SUDO=true make`.

## Installation

If [available in Hex](https://hex.pm/docs/publish), the package can be installed as:

  1. Add `nerves_network_interface` to your list of dependencies in `mix.exs`:

        def deps do
          [{:nerves_network_interface, "~> 0.3.2"}]
        end

  2. List `:nerves_network_interface` as an application dependency:

        def application do
          [applications: [:nerves_network_interface]]
        end

  3. Run `mix deps.get` and `mix compile`

## Permissions

If an application just needs to get information about LAN interfaces,
this library does not require any additional privileges. If it is necessary
to modify the network interfaces, the same privilege needed to run applications
like `ifconfig` and `ip` will be needed. This can be accomplished by setting
the `netif` binary to be setuid root. E.g.,

    chown root:root priv/netif
    chmod +s priv/netif

Keep in mind that running `setuid` on the netif port binary could have
security implications in your system. The `Makefile` will automatically call
`sudo` to do this, but that can be disabled.

If you do not require additional privileges to modify network
interfaces on your system, you can bypass the calls to `sudo` by setting the
SUDO environment variable to `true`. I.e., `SUDO=true make`.

## Running

Start `iex`:

    $ iex -S mix

The `Nerves.NetworkInterface` application will start automatically.

To see which interfaces are available, call `Nerves.NetworkInterface.interfaces\0`:

    iex> Nerves.NetworkInterface.interfaces
	['lo', 'eth0', 'wlan0']

To get link-level status information and statistics on an interface, call
`Nerves.NetworkInterface.status/1`:

    iex> Nerves.NetworkInterface.status "eth0"
    {:ok, %{ifname: 'eth0', index: 2, is_broadcast: true, is_lower_up: true,
            is_multicast: true, is_running: true, is_up: true,
            mac_address: <<224, 219, 85, 231, 139, 93>>,
            mac_broadcast: <<255, 255, 255, 255, 255, 255>>, mtu: 1500, operstate: :up,
            stats: %{collisions: 0, multicast: 7, rx_bytes: 2561254, rx_dropped: 0,
              rx_errors: 0, rx_packets: 5301, tx_bytes: 944159, tx_dropped: 0,
              tx_errors: 0, tx_packets: 3898}, type: :ethernet}

Polling `Nerves.NetworkInterface` for status isn't that great, so it's possible to
register a `GenEvent` with `Nerves.NetworkInterface`.

*This will change in the future. GenEvent use will be removed.*

The following example shows how to view events at the prompt:

    iex> defmodule Forwarder do
    ...>  use GenEvent
    ...>  def handle_event(event, parent) do
    ...>    send parent, event
    ...>    {:ok, parent}
    ...>  end
    ...> end
    iex> Nerves.NetworkInterface.event_manager |> GenEvent.add_handler(Forwarder, self())
    :ok
    iex> flush
    :ok
    # Plug Ethernet cable in
    iex> flush
    {:nerves_network_interface, #PID<0.62.0>, :ifchanged,
     %{ifname: 'eth0', index: 2, is_broadcast: true, is_lower_up: true,
       is_multicast: true, is_running: true, is_up: true,
       mac_address: <<224, 219, 85, 231, 139, 93>>,
       mac_broadcast: <<255, 255, 255, 255, 255, 255>>, mtu: 1500, operstate: :up,
       stats: %{collisions: 0, multicast: 14, rx_bytes: 3061718, rx_dropped: 0,
         rx_errors: 0, rx_packets: 7802, tx_bytes: 1273557, tx_dropped: 0,
         tx_errors: 0, tx_packets: 5068}, type: :ethernet}}

Events sent by `Nerves.NetworkInterface` include:
  * `ifadded` - an interface was hotplugged (e.g., a USB wifi dongle)
  * `ifrenamed` - an interface was renamed (e.g., `wlan0` is now
    `wlxc83a35ca5f10`
  * `ifchanged` - an interface changed statue (e.g., it was down, but now it's
    up)
  * `ifremoved` - an interface was removed (e.g., the user removed a USB wifi
    dongle)

To get the IP configuration for an interface, call `Nerves.NetworkInterface.settings/1`:

    iex> Nerves.NetworkInterface.settings "eth0"
    {:ok, %{ipv4_address: '192.168.25.114', ipv4_broadcast: '192.168.25.255',
            ipv4_gateway: '192.168.25.5', ipv4_subnet_mask: '255.255.255.0'}

To setting IP addresses and other configuration, just call
`Nerves.NetworkInterface.setup/2` using keyword parameters or a map with what you'd like
to set. The following example uses keyward parameters:

    iex> Nerves.NetworkInterface.setup "eth0", ipv4_address: "192.168.25.200", ipv4_subnet_mask: "255.255.255.0")
    :ok

If you get an error, check that you are running Elixir with sufficient privilege
to modify network interfaces or make the `netif` binary setuid root.

The library accepts both Erlang strings and Elixir strings. It,
however, only returns Elixir strings.

To enable or disable an interface, you can do so with `Nerves.NetworkInterface.ifup/1` and
`Nerves.NetworkInterface.ifdown/1`. As you would expect, these require privilege to run:

    iex> Nerves.NetworkInterface.ifdown "eth0"
    :ok

## Licensing

This package is licensed under the Apache 2.0 license.