Net::I...veloper(3pm)
πΈ Net::Interface::Developer πΈ
okay bestie, so we're reading Net::Interface::Developer(3pm) β it's part of the User Contributed Perl Documentation and it's the developer page. like, this is the one you read when you wanna poke at the internals. buckle up π«Ά
β¨ NAME β¨
Net::Interface::Developer β api, notes, hints
π¦ DESCRIPTION π¦
so basically this page is where all the development notes and API documentation for the Net::Interface module live. and the whole vibe is: please, please help fill in the missing pieces for OS's and address families that currently don't have support yet. it's giving "community project, open invite, no gatekeeping" π
π ARCHITECTURE π
okay so the way Net::Interface does its thing: it gathers info about the network interfaces in an OS-independent way. how? it first tries getifaddrs. and if getifaddrs isn't supported on that OS, it falls back to system ioctl's and the ifreq, in6_ifreq, lifreq structures that are defined on the local host.
Linux is a lil different though β ipV6 info is only available directly from the kernel on older versions where getifaddrs isn't available. so the ifreq and friends info gets used to generate a getifaddrs response. it's giving "we improvise, we adapt, we slay" π
and THIS, bestie, is exactly why the opensource community needs to keep developing this. so many OS's have peculiar ioctl variants and SIOC's variants that need their own unique code solutions. the author is like "I'm sure not all of them are presently included" β and honestly? fair.
Net::Interface is built in 5 layers, from the base on up. here's the lineup:
description: files code
1) AF_xxx families: ni_af_inetcommon.c (C)
- AF_xxx families β
ni_af_inetcommon.c(C)
these are the code modules for AF families. currently supported: AF_INET, AF_INET6. there's partial support for AF_LINK and AF_PACKET so we can retrieve the MAC address from the interface where it's needed. and whenever the code is reasonably universal for a particular address family and for the methods used to pull the info off the OS, it lives in an af_xxxx.c file. iconic behavior β¨
- IFREQ families β
ni_xx_ifreq.c(C)
code modules for IFREQ families. currently supported are:
ifreqβni_ifreq.c
supports retrieval of ipV4 information. the ifreq structure just doesn't have enough space to return data about socket address families bigger than struct sockaddr. also, all known operating systems support this flavor of data retrieval, so it's the universal one. ni_ifreq.c makes use of calls to ni_af_inet.c.
in6_ifreqβni_in6_ifreq.c
supports retrieval of both ipV4 and ipV6 information. in6_ifreq uses struct sockaddr_storage instead of the smaller struct sockaddr that ifreq uses. this code module supports 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
supports retrieval of both ipV4 and ipV6 information. lifreq has a custom format unique to the SUN operating systems. pretty much everything in it, even though it's similar to the two previous code modules, is custom. it's giving "we do our own thing here" π
linuxprocβni_linuxproc.c
supports retrieval of both ipV4 and ipV6 information. linuxproc uses calls to ni_af_inet.c to get ipV4 information into getifaddrs format, plus custom code to collect similarly formatted ipV6 information directly from the /proc file system. then it performs a merge on these two data sets to put them in proper order, and adds fake AF_LINK or AF_PACKET records so you get getifaddrs-compatible access to the MAC address through the returned struct ifaddrs array. obsessed π
getifaddrsβni_getifaddrs.c(C)
the getifaddrs code module holds the decision mechanism for how data gets retrieved for a particular build of Net::Interface. at build time, portions of the code are #ifdef'd in/out depending on the availability of resources from the underlying OS. and in addition, at run time, if the system doesn't have native getifaddrs, then a decision tree kicks in based on the response to calls for data to the various code modules described in section 2. it's giving "runtime detective work" π₯
- Sub-system β
Interface.xs(PERLXS)
this file asks for the data about the interfaces with a generic call to getifaddrs. the data returned lives in memory allocated by the OS, and it must be freed or a memory leak will result, because it is not tracked by Perl's garbage collector. Interface.xs moves the interface data from allocated memory into 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. no leaks, no drama, no cap π―
- User space β
Interface.pm(Perl)
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.
π DATA FLOW BLOCK DIAGRAM π
here's the whole vibe in diagram form, bestie. it's giving β¨main character energyβ¨:
*\ \ \ | / / /*
* 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 code 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, so you can do code creation and debug. currently the ref is unused. it's expected that future development will modify or add to the function access. iykyk πΈ
# 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've gotten this far, bestie, 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);
a 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)
like:
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 β¨
okay bestie, this is the part where it gets juicy β all the actual C functions this module hands you. buckle up π
int ni_clos_reopn_dgrm(int fd, int af)
This one closes a socket and then immediately opens an ioctl socket of type SOCK_DGRAM, handing you back the socket value β¨.
Small but important plot twist: if that socket value comes back NEGATIVE, no close ever happened, and the call is literally just the same as doing:
socket(af,SOCK_DGRAM,0)
so yeah, she tried, she closed nothing, she's just a socket() call in a trench coat π
void ni_gifa_free(struct ifaddrs * ifap, int flavor)
Different getifaddrs flavors need different free functions, bestie β so you hand this girl the ifaddrs structure list and the flavor it came from, and she calls the appropriate free memory function for you. no mismatched free/alloc energy here, we do not do that π
int nifreq_gifaddrs(struct ifaddrs **ifap, struct ni_ifconf_flavor *nifp)
This is our semi-standard version of getifaddrs, the one that gets used by OS's that hand you ifreq and in6_ifreq instead of the nice stuff πΈ
NOTE: all calls togetifaddrsreturn-1on failure and the FLAVOR as enumerated above on success.
like, for real for real:
i.e. NI_NULL for the native getifaddrs, NI_IFREQ, NI_LINUXPROC, etc...
so check the flavor, that's your iykyk moment π
uint32_t ni_ipv6addr_gettype(struct in6_addr * in6p)
She reaches into an ipV6 address and extracts info about what type of address it is π¦. The value she hands back? You can pass it straight into the NEXT function call to print it. chain reaction, main character energy, we love a handoff β¨
int ni_lx_map2scope(int lscope)
This maps Linux style scope bits to their RFC-2373 equivalent. here's the whole vibe check:
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 π. and the table she's pulling from is iconic, look at this:
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" }
};
no cap, she ate π
int ni_sizeof_type2txt()
Returns the size of the above table. tiny function, huge support role, the bestie who holds your bag while you slay π«Ά
u_int ni_get_scopeid(struct sockaddr_in6 * sin6)
On systems using KAME, she extracts and returns the scope from field 2 of the ipV6 address, and sets fields 2,3 to zero π§. On all other systems she just returns:
sin6->sin6_scopeid
and here's the scope flags table, because of course there's a table:
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)
Allocates memory for size and copies the contents from memp π. Returns NULL on error, and sets errno to ENOMEM. so if you get NULL back, that's the memory gods saying "not today" π
void ni_plen2mask(void * in_addr, int plen, int sizeofaddr)
Creates a NETMASK string from a prefix length β¨. usage:
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)
Calculates 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 π¦. usage:
For ipV4:
ni_prefix(&in_addr,sizeof(struct in_addr));
For ipV6:
ni_prefix(&in6_addr,sizeof(struct(in6_addr));
(yes bestie, those are copied character for character β do not come for me, I am simply the messenger π )
int ni_refresh_ifreq(int fd, struct ifconf *ifc, void **oifr, void **olifr, struct ni_ifconf_flavor * nifp)
So some OS's just lose scope on the particular device/addr handle when certain ioctl's get performed. rude honestly. This function refreshes the ifconf chain and repositions the pointers in the exact same spot, but now with fresh scope π.
Wanna see it in the wild? See ni_in6_ifreq.c and ni_af_net6.c for usage β search for the string refreshifr. The 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.
and that's the whole page, bestie π«Ά this part two came from perl v5.42.3, dated 2026-08-19, and it lives under the Net::I...veloper(3pm) page in the User Contributed Perl Documentation β¨ go forth and refresh those ifreq chains, you absolute queen ππ
π¦ where this page comes from
- ubuntu stonking: libnet-interface-perl 1.016-4build1 Β· Artistic-1.0-Perl OR GPL-2.0-or-later
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms