---
name: "Net::Interface::Developer"
section: "3pm"
platform: "linux"
package: "libnet-interface-perl"
version: "1.016-3+b2"
release: "Debian 13 (Trixie)"
platforms: ["linux"]
url: "https://new.carta.tech/Net::Interface::Developer"
---

# Net::Interface::Developer(3pm)

api, notes, hints

## NAME

Net::Interface::Developer - api, notes, hints

## DESCRIPTION

This contains development notes and API documentation for the Net::Interface module. It is hoped that others will help fill in the missing pieces for OS's and address families that are currently unsupported.

## ARCHITECTURE

Net::Interface gathers information about the network interfaces in an OS independent fashion by first attempting to use `"getifaddrs"` if `"getifaddrs"` is not supported on the OS it falls back to using system `"ioctl's"` and the `"ifreq, in6_ifreq, lifreq"` structures defined on the local host. Linux differs somewhat since ipV6 information is available only directly from the kernel on older versions where `"getifaddrs"` is not available. The `"ifreq"` and friends information is used to generate a `"getifaddrs"` response.

Herein lies the need for continued development by the opensource community. Many OS's have peculiar `"ioctl"` variants and SIOC's variants that require unique code solutions. I'm sure that all of them are not presently included.

Net::Interface is built in 5 layers, listed below from the base up.

### description: files code

### 1) AF\_xxx families: ni\_af\_inetcommon.c (C)

Code modules for AF families. Currently supported are AF\_INET, AF\_INET6. There is partial support for AF\_LINK and AF\_PACKET for retrieval of MAC address from the interface where it is needed. Where the code is reasonably universal for a particular address family and the methods used to retrieve the information from the OS, it resides in an af\_xxxx.c file.

### 2) IFREQ families: ni\_xx\_ifreq.c (C)

Code modules for IFREQ families. Currently supported are:

- •

  `"ifreq"` ni\_ifreq.c

  Provides support for retrieval of ipV4 information. The structure `"ifreq"` does not provide enough space to return data about socket address families larger than `"struct sockaddr"`. All known operating systems support this flavor of data retrieval. ni\_ifreq.c makes use of calls to ni\_af\_inet.c

- •

  `"in6_ifreq"` ni\_in6\_ifreq.c

  Provides support for retrieval of both ipV4 and ipV6 information. `"in6_ifreq"` uses `"struct sockaddr_storage"` rather than the smaller `"struct sockaddr"` that is used in `"ifreq"`. This code modules support variants of the BSD operating system and a few others. ni\_in6\_ifreq makes use of calls to ni\_af\_inetcommon.c

- •

  `"lifreq"` ni\_lifreq.c

  Provides support for retrieval of both ipV4 and ipV6 information. `"lifreq"` has a custom format unique to the SUN operating systems. Pretty much everything in it, while similar to the two previous code modules, is custom.

- •

  `"linuxproc"` ni\_linuxproc.c

  Provides support for retrieval of both ipV4 and ipV6 information. `"linuxproc"` uses calls to ni\_af\_inet.c to get ipV4 information int `"getifaddrs"` format and custom code to collect similarly formatted ipV6 information directly from the /proc file system. It then performs a merge on these two data sets to put them into proper order and add **fake** AF\_LINK or AF\_PACKET records to provide `"getifaddrs"` compatiable access to the MAC address through the returned `"struct ifaddrs"` array.

### 3) "getifaddrs" ni\_getifaddrs.c (C)

The `"getifaddrs"` code module contains the decision mechanism for how data is retrieved for a particular build of Net::Interface. At build time, portions of the code are #ifdef'd in/out depending on the availabiltiy of resource from the underlying OS. In addition, at run time, if the system does not have native `"getifaddrs"` then a decision tree is used depending on the response to calls for data to the various code modules described in section 2).

### 4) Sub-system Interface.xs (PERLXS)

This file asks for the data about the interfaces with a generic call to `"getifaddrs"`. The data returned resides in memory allocated by the OS and must be freed or a memory leak will result as it is not tracked by Perl's garbage collector. `"Interface.xs"` moves the interface data from allocated memory to Perl managed memory where it can be reclaimed by the garbage collection mechanism if/when the user space program turns it loose. This eliminates the need for a `"close"` operation to free the OS's allocated memory.

### 5) User space Interface.pm (Perl)

## DATA FLOW BLOCK DIAGRAM

The pure perl portion of this module performs most of the presentation operations for the user that are published in the API for Net::Interface.

```
        *\  \  \    |    /  /  /*
        *      user space       *
        *************************
                    ^                                Net::Interface
                    |                           Architecture Block Diagram
                    v
        *************************
        *      Interface.pm     *
        *************************
                    |
        *************************
        *      Interface.xs     *
        *************************
                    |
        *************************               *************************
        *   system getifaddrs   *               *      ni_getifreqs     *
        *          via          *<-if missing ->*           via         *
        *   (ni_getifaddrer.c)  *               *    (ni_ifreq.c)       *
        *************************               *    (ni_lifreq.c)      *
                                                *    (ni_in6_ifreq.c)   *
                                                *    (ni_linuxproc.c)   *
                                                *************************
                                                            |
                                                *************************
                                                *  (ni_af_inetcommon.c) *
                                                *************************
```

## DEVELOPER API

Access to the pieces of code in the block diagram above are available through a developer API. These codes snippets from Interfaces.xs describe the access.

```
 void
 __developer(ref)
        SV *ref
    ALIAS:
        d_ni_ifreq      = NI_IFREQ
        d_ni_lifreq     = NI_LIFREQ
        d_ni_in6_ifreq  = NI_IN6_IFREQ
        d_ni_linuxproc  = NI_LINUXPROC
    PREINIT:
        char * process;
        int er = ni_developer(ix);
```

**and.....**

```
 void
 gifaddrs_base(ref)
        SV * ref
    ALIAS:
 #      base            = 0
        gifa_ifreq      = NI_IFREQ
        gifa_lifreq     = NI_LIFREQ
        gifa_in6_ifreq  = NI_IN6_IFREQ
        gifa_linuxproc  = NI_LINUXPROC
    PREINIT:
        struct ifaddrs * ifap;
        int rv;
    CODE:
        if ((rv = ni_getifaddrs(&ifap,ix)) == -1) {
            printf("failed PUNT!\n");
            XSRETURN_EMPTY;
```

Both function sets result in a printed description to the terminal window to facilitate code creation and debug. Currently the **ref** is unused. It is expected that future development will modify or add to function access.

```
  # test.pl for developer
  #
  use strict;
  use Net::Interface;
  # to call OS native getifaddrs if present
  print "\nifreq\n";  gifaddrs_base Net::Interface();
  # to call ni_linuxproc fallback getifaddrs
  print "\nlxp\n";    gifa_linuxproc Net::Interface();
  # to call ni_linuxproc ifreq emulation
  print "\nglxp\n";   d_ni_linuxproc Net::Interface();
```

See: test.pl.developer

## DEVELOPER API DESCRIPTION

If you have gotten this far, it is time to read some of the code. AF\_familes and IFREQ\_families are accessed through constructor structs found at the bottom of each of the ni\_af\_xxx and ni\_xx\_ifreq source files. Their vectoring components are described in `"ni_func.h"` near the bottom and in `"ni_util.c"` in the section labeled **constructor registration** the essence of which is described here.

```
  struct ni_ifconf_flavor * ni_ifcf_get(enum ni_FLAVOR type)
  struct ni_ifconf_flavor * ni_safe_ifcf_get(enum ni_FLAVOR type);
  nifp = ni_ifcf_get(NI_IFREQ);
```

Returns a pointer `"nifp"` to the structure for a particular flavor of **ifreq**. If a flavor is unsupported on a particular architecture a NULL is returned by the first invocation and NI\_IFREQ by the second.  Currently supported flavors are:

```
  enum ni_FLAVOR {
        NI_NULL,        reserved for the getifaddrs base system call
        NI_IFREQ,
        NI_LIFREQ,
        NI_IN6_IFREQ,
        NI_LINUXPROC
  };
  struct ni_ifconf_flavor {
    enum ni_FLAVOR              ni_type;
    int                         (*gifaddrs)
    int                         siocgifindex;
    int                         siocsifaddr;
    int                         siocgifaddr;
    int                         siocdifaddr;
    int                         siocaifaddr;
    int                         siocsifdstaddr;
    int                         siocgifdstaddr;
    int                         siocsifflags;
    int                         siocgifflags;
    int                         siocsifmtu;
    int                         siocgifmtu;
    int                         siocsifbrdaddr;
    int                         siocgifbrdaddr;
    int                         siocsifnetmask;
    int                         siocgifnetmask;
    int                         siocsifmetric;
    int                         siocgifmetric;
    int                         ifr_offset;
    void                        (*fifaddrs)      howto free ifaddrs
    int                         (*refreshifr)    howto refresh ifreq
    void *                      (*getifreqs)     howto get ifreq
    int                         (*developer)     developer access
    struct ni_ifconf_flavor *   ni_ifcf_next;
  };
```

## MACROS

- NI\_PRINT\_MAC(u\_char \* hex\_mac\_string);

  ```
    printf statement for terminal output of the form
          XX:XX:XX:XX:XX:XX:XX:XX
  ```

- NI\_MAC\_NOT\_ZERO(u\_char \* hex\_mac\_string)

  ```
    if( NI_MAC_NOT_ZERO(macp))
          do something
  ```

- NI\_PRINT\_IPV6(struct sin6\_addr);

  ```
    Takes an argument of the form sockaddr_in6.sin6_addr and prints
          XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX
  ```

## FUNCTIONS

- int ni\_clos\_reopn\_dgrm(int fd, int af)

  Closes and then opens an `"ioctl"` socket of type SOCK\_DGRAM and returns the socket value. If the socket value is NEGATIVE, no close is attempted an the call is equivalent to:

  ```
    socket(af,SOCK_DGRAM,0)
  ```

- void ni\_gifa\_free(struct ifaddrs \* ifap, int flavor)

  Use the appropriate free memory function call depending on the flavor of the getifaddrs function that returned the ifaddrs structure list.

- int nifreq\_gifaddrs(struct ifaddrs \*\*ifap, struct ni\_ifconf\_flavor \*nifp)

  Our semi-standard version of `"getifaddrs"` used by OS's that provide `"ifreq"` and `"in6_ifreq"`.

  NOTE: all calls to `"getifaddrs"` return -1 on failure and and the FLAVOR as enumerated above on success.

  ```
    i.e. NI_NULL for the native getifaddrs, NI_IFREQ, NI_LINUXPROC, etc...
  ```

- uint32\_t ni\_ipv6addr\_gettype(struct in6\_addr \* in6p)

  Extracts information about the type of ipV6 address. The returned value may be passed to the NEXT function call to print.

- int ni\_lx\_map2scope(int lscope)

  This function maps *Linux* style scope bits to their RFC-2373 equivalent.

  ```
      scope flags rfc-2373
          0       reserved
          1    node-local (aka loopback, interface-local)
          2    link-local
          3       unassigned
          4       unassigned
          5    site-local
          6       unassigned
          7       unassigned
          8    organization-local
          9       unassigned
          A       unassigned
          B       unassigned
          C       unassigned
          D       unassigned
          E    global scope
          F       reserved
        Linux   rfc-2372
       0x0000     0xe     GLOBAL
       0x0010u    0x1     NODELOCAL, LOOPBACK, INTERFACELOCAL
       0x0020u    0x2     LINKLOCAL
       0x0040u    0x5     SITELOCAL
  ```

- void ni\_linux\_scope2txt(uint32\_t type)

  Print information about an ipV6 address for each bit present in `"type"`.

  ```
    const ni_iff_t ni_lx_type2txt[] = {
          { IPV6_ADDR_ANY,                "unknown" },
          { IPV6_ADDR_UNICAST,            "unicast" },
          { IPV6_ADDR_MULTICAST,          "multicast" },
          { IPV6_ADDR_ANYCAST,            "anycast" },
          { IPV6_ADDR_LOOPBACK,           "loopback" },
          { IPV6_ADDR_LINKLOCAL,          "link-local" },
          { IPV6_ADDR_SITELOCAL,          "site-local" },
          { IPV6_ADDR_COMPATv4,           "compat-v4" },
          { IPV6_ADDR_SCOPE_MASK,         "scope-mask" },
          { IPV6_ADDR_MAPPED,             "mapped" },
          { IPV6_ADDR_RESERVED,           "reserved" },
          { IPV6_ADDR_ULUA,               "uniq-lcl-unicast" },
          { IPV6_ADDR_6TO4,               "6to4" },
          { IPV6_ADDR_6BONE,              "6bone" },
          { IPV6_ADDR_AGU,                "global-unicast" },
          { IPV6_ADDR_UNSPECIFIED,        "unspecified" },
          { IPV6_ADDR_SOLICITED_NODE,     "solicited-node" },
          { IPV6_ADDR_ISATAP,             "ISATAP" },
          { IPV6_ADDR_PRODUCTIVE,         "productive" },
          { IPV6_ADDR_6TO4_MICROSOFT,     "6to4-ms" },
          { IPV6_ADDR_TEREDO,             "teredo" },
          { IPV6_ADDR_ORCHID,             "orchid" },
          { IPV6_ADDR_NON_ROUTE_DOC,      "non-routeable-doc" }
    };
  ```

- int **ni\_sizeof\_type2txt()**

  Returns the size of the above table.

- u\_int ni\_get\_scopeid(struct sockaddr\_in6 \* sin6)

  On systems using KAME, this function extracts and returns the scope from field 2 of the ipV6 address and sets fields 2,3 to zero. On all other systems it returns

  ```
          sin6->sin6_scopeid
     scope flags     rfc-2373
          0         reserved
          1       node-local
          2       link-local
          3         unassigned
          4         unassigned
          5       site-local
          6         unassigned
          7         unassigned
          8       organization-local
          9         unassigned
          A         unassigned
          B         unassigned
          C         unassigned
          D         unassigned
          E       global scope
          F         reserved
  ```

- void \* ni\_memdup(void \*memp, int size)

  Allocate memory of for **size** and copy contents from **memp**. Returns NULL on error and sets **errno** to ENOMEM.

- void ni\_plen2mask(void \* in\_addr, int plen, int sizeofaddr)

  Create a NETMASK string from a prefix length

  For ipV4: ni\_plen2mask(&in\_addr, cidr, sizeof(struct in\_addr));

  For ipV6: ni\_plen2mask(&in6\_addr, cidr, sizeof(struct in6\_addr));

- int ni\_prefix(void \* ap, int len, int size)

  Calculated the prefix length for a NETMASK where \*ap points to the binary representation of the NETMASK and size is the number of bytes in the mask.

  For ipV4: ni\_prefix(&in\_addr,sizeof(struct in\_addr));

  For ipV6: ni\_prefix(&in6\_addr,sizeof(struct(in6\_addr));

- int ni\_refresh\_ifreq(int fd, struct ifconf \*ifc, void \*\*oifr, void \*\*olifr, struct ni\_ifconf\_flavor \* nifp)

  Some OS lose scope on the particular device/addr handle when certain ioctl's are performed. This function refreshs the ifconf chain and positions the pointers in the exact same spot with fresh scope.

  See ni\_in6\_ifreq.c and ni\_af\_net6.c for usage. Search for the string **refreshifr**. Code snippit looks like:

  ```
          nifp->refreshir
  ```

## COPYRIGHT

```
        Copyright 2008-2009 - Michael Robinton
```

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; either version 2, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License in the file named "Copying" for more details.

You should also have received a copy of the GNU General Public License along with this program in the file named "Copying". If not, write to the

```
        Free Software Foundation, Inc.
        59 Temple Place, Suite 330
        Boston, MA  02111-1307, USA
```

or visit their web page on the internet at:

```
        http://www.gnu.org/copyleft/gpl.html.
```
