From 0b3a4c5e5c308b3d81ecb73fdf0030c150af3ed6 Mon Sep 17 00:00:00 2001 From: Arnaud Loonstra Date: Tue, 28 Feb 2023 18:38:11 +0100 Subject: [PATCH] Feature: adding macaddress to ziflist items (#2259) --- AUTHORS | 1 + api/python_cffi.slurp | 4 + api/ziflist.api | 5 + bindings/delphi/CZMQ.pas | 11 ++ bindings/delphi/libczmq.pas | 3 + .../src/main/c/org_zeromq_czmq_Ziflist.c | 8 ++ .../main/java/org/zeromq/czmq/Ziflist.java | 7 ++ bindings/lua_ffi/czmq_ffi.lua | 4 + bindings/nodejs/README.md | 6 ++ bindings/nodejs/binding.cc | 7 ++ bindings/nodejs/binding.h | 1 + bindings/python/czmq/_czmq_ctypes.py | 8 ++ bindings/python_cffi/czmq_cffi/Ziflist.py | 6 ++ bindings/python_cffi/czmq_cffi/cdefs.py | 4 + bindings/qml/src/QmlZiflist.cpp | 6 ++ bindings/qml/src/QmlZiflist.h | 3 + bindings/qt/src/qziflist.cpp | 8 ++ bindings/qt/src/qziflist.h | 3 + bindings/ruby/lib/czmq/ffi.rb | 1 + bindings/ruby/lib/czmq/ffi/ziflist.rb | 10 ++ include/czmq_prelude.h | 9 ++ include/ziflist.h | 5 + src/czmq_classes.h | 5 + src/ziflist.c | 102 ++++++++++++++++-- 24 files changed, 220 insertions(+), 7 deletions(-) diff --git a/AUTHORS b/AUTHORS index 2abd63182..504804dca 100644 --- a/AUTHORS +++ b/AUTHORS @@ -67,3 +67,4 @@ Michal Hrusecky Alena Chernikava Stephen Procter Wes Young +Arnaud Loonstra diff --git a/api/python_cffi.slurp b/api/python_cffi.slurp index d0a73bcbf..4c166edc4 100644 --- a/api/python_cffi.slurp +++ b/api/python_cffi.slurp @@ -1625,6 +1625,10 @@ const char * const char * ziflist_netmask (ziflist_t *self); +// Return the current interface MAC address as a printable string +const char * + ziflist_mac (ziflist_t *self); + // Return the list of interfaces. void ziflist_print (ziflist_t *self); diff --git a/api/ziflist.api b/api/ziflist.api index ed69a9b40..457791076 100644 --- a/api/ziflist.api +++ b/api/ziflist.api @@ -52,6 +52,11 @@ + + Return the current interface MAC address as a printable string + + + Return the list of interfaces. diff --git a/bindings/delphi/CZMQ.pas b/bindings/delphi/CZMQ.pas index f4d98eeba..c8698a327 100644 --- a/bindings/delphi/CZMQ.pas +++ b/bindings/delphi/CZMQ.pas @@ -892,6 +892,9 @@ interface // Return the current interface network mask as a printable string function Netmask: string; + // Return the current interface MAC address as a printable string + function Mac: string; + // Return the list of interfaces. procedure Print; @@ -3617,6 +3620,9 @@ TZiflist = class(TInterfacedObject, IZiflist) // Return the current interface network mask as a printable string function Netmask: string; + // Return the current interface MAC address as a printable string + function Mac: string; + // Return the list of interfaces. procedure Print; @@ -7661,6 +7667,11 @@ function ZFreeString(const str: PAnsiChar): string; Result := string(UTF8String(ziflist_netmask(FHandle))); end; + function TZiflist.Mac: string; + begin + Result := string(UTF8String(ziflist_mac(FHandle))); + end; + procedure TZiflist.Print; begin ziflist_print(FHandle); diff --git a/bindings/delphi/libczmq.pas b/bindings/delphi/libczmq.pas index 61beabcc6..d44037c23 100644 --- a/bindings/delphi/libczmq.pas +++ b/bindings/delphi/libczmq.pas @@ -1315,6 +1315,9 @@ interface // Return the current interface network mask as a printable string function ziflist_netmask(self: PZiflist): PAnsiChar; cdecl; external lib_czmq {$IFDEF MSWINDOWS}delayed{$ENDIF}; + // Return the current interface MAC address as a printable string + function ziflist_mac(self: PZiflist): PAnsiChar; cdecl; external lib_czmq {$IFDEF MSWINDOWS}delayed{$ENDIF}; + // Return the list of interfaces. procedure ziflist_print(self: PZiflist); cdecl; external lib_czmq {$IFDEF MSWINDOWS}delayed{$ENDIF}; diff --git a/bindings/jni/czmq-jni/src/main/c/org_zeromq_czmq_Ziflist.c b/bindings/jni/czmq-jni/src/main/c/org_zeromq_czmq_Ziflist.c index a3e414e5b..59116ce6d 100644 --- a/bindings/jni/czmq-jni/src/main/c/org_zeromq_czmq_Ziflist.c +++ b/bindings/jni/czmq-jni/src/main/c/org_zeromq_czmq_Ziflist.c @@ -78,6 +78,14 @@ Java_org_zeromq_czmq_Ziflist__1_1netmask (JNIEnv *env, jclass c, jlong self) return return_string_; } +JNIEXPORT jstring JNICALL +Java_org_zeromq_czmq_Ziflist__1_1mac (JNIEnv *env, jclass c, jlong self) +{ + char *mac_ = (char *) ziflist_mac ((ziflist_t *) (intptr_t) self); + jstring return_string_ = (*env)->NewStringUTF (env, mac_); + return return_string_; +} + JNIEXPORT void JNICALL Java_org_zeromq_czmq_Ziflist__1_1print (JNIEnv *env, jclass c, jlong self) { diff --git a/bindings/jni/czmq-jni/src/main/java/org/zeromq/czmq/Ziflist.java b/bindings/jni/czmq-jni/src/main/java/org/zeromq/czmq/Ziflist.java index 235ad8b60..57eaf3a0a 100644 --- a/bindings/jni/czmq-jni/src/main/java/org/zeromq/czmq/Ziflist.java +++ b/bindings/jni/czmq-jni/src/main/java/org/zeromq/czmq/Ziflist.java @@ -96,6 +96,13 @@ public String netmask () { return __netmask (self); } /* + Return the current interface MAC address as a printable string + */ + native static String __mac (long self); + public String mac () { + return __mac (self); + } + /* Return the list of interfaces. */ native static void __print (long self); diff --git a/bindings/lua_ffi/czmq_ffi.lua b/bindings/lua_ffi/czmq_ffi.lua index b95ceaa97..30dc3e016 100644 --- a/bindings/lua_ffi/czmq_ffi.lua +++ b/bindings/lua_ffi/czmq_ffi.lua @@ -1620,6 +1620,10 @@ const char * const char * ziflist_netmask (ziflist_t *self); +// Return the current interface MAC address as a printable string +const char * + ziflist_mac (ziflist_t *self); + // Return the list of interfaces. void ziflist_print (ziflist_t *self); diff --git a/bindings/nodejs/README.md b/bindings/nodejs/README.md index 213048900..a4e1de1ac 100644 --- a/bindings/nodejs/README.md +++ b/bindings/nodejs/README.md @@ -1691,6 +1691,12 @@ string my_ziflist.netmask () Return the current interface network mask as a printable string +``` +string my_ziflist.mac () +``` + +Return the current interface MAC address as a printable string + ``` nothing my_ziflist.print () ``` diff --git a/bindings/nodejs/binding.cc b/bindings/nodejs/binding.cc index ed9789dfb..fcdf079d8 100644 --- a/bindings/nodejs/binding.cc +++ b/bindings/nodejs/binding.cc @@ -3261,6 +3261,7 @@ NAN_MODULE_INIT (Ziflist::Init) { Nan::SetPrototypeMethod (tpl, "address", _address); Nan::SetPrototypeMethod (tpl, "broadcast", _broadcast); Nan::SetPrototypeMethod (tpl, "netmask", _netmask); + Nan::SetPrototypeMethod (tpl, "mac", _mac); Nan::SetPrototypeMethod (tpl, "print", _print); Nan::SetPrototypeMethod (tpl, "newIpv6", _new_ipv6); Nan::SetPrototypeMethod (tpl, "reloadIpv6", _reload_ipv6); @@ -3344,6 +3345,12 @@ NAN_METHOD (Ziflist::_netmask) { info.GetReturnValue ().Set (Nan::New (result).ToLocalChecked ()); } +NAN_METHOD (Ziflist::_mac) { + Ziflist *ziflist = Nan::ObjectWrap::Unwrap (info.Holder ()); + char *result = (char *) ziflist_mac (ziflist->self); + info.GetReturnValue ().Set (Nan::New (result).ToLocalChecked ()); +} + NAN_METHOD (Ziflist::_print) { Ziflist *ziflist = Nan::ObjectWrap::Unwrap (info.Holder ()); ziflist_print (ziflist->self); diff --git a/bindings/nodejs/binding.h b/bindings/nodejs/binding.h index cc06c7cb6..c1dd404f5 100644 --- a/bindings/nodejs/binding.h +++ b/bindings/nodejs/binding.h @@ -445,6 +445,7 @@ class Ziflist: public Nan::ObjectWrap { static NAN_METHOD (_address); static NAN_METHOD (_broadcast); static NAN_METHOD (_netmask); + static NAN_METHOD (_mac); static NAN_METHOD (_print); static NAN_METHOD (_new_ipv6); static NAN_METHOD (_reload_ipv6); diff --git a/bindings/python/czmq/_czmq_ctypes.py b/bindings/python/czmq/_czmq_ctypes.py index 74958050d..604de3b9e 100644 --- a/bindings/python/czmq/_czmq_ctypes.py +++ b/bindings/python/czmq/_czmq_ctypes.py @@ -3451,6 +3451,8 @@ def test(verbose): lib.ziflist_broadcast.argtypes = [ziflist_p] lib.ziflist_netmask.restype = c_char_p lib.ziflist_netmask.argtypes = [ziflist_p] +lib.ziflist_mac.restype = c_char_p +lib.ziflist_mac.argtypes = [ziflist_p] lib.ziflist_print.restype = None lib.ziflist_print.argtypes = [ziflist_p] lib.ziflist_new_ipv6.restype = ziflist_p @@ -3552,6 +3554,12 @@ def netmask(self): """ return lib.ziflist_netmask(self._as_parameter_) + def mac(self): + """ + Return the current interface MAC address as a printable string + """ + return lib.ziflist_mac(self._as_parameter_) + def print(self): """ Return the list of interfaces. diff --git a/bindings/python_cffi/czmq_cffi/Ziflist.py b/bindings/python_cffi/czmq_cffi/Ziflist.py index b2feb4eab..780af1674 100644 --- a/bindings/python_cffi/czmq_cffi/Ziflist.py +++ b/bindings/python_cffi/czmq_cffi/Ziflist.py @@ -66,6 +66,12 @@ def netmask(self): """ return utils.lib.ziflist_netmask(self._p) + def mac(self): + """ + Return the current interface MAC address as a printable string + """ + return utils.lib.ziflist_mac(self._p) + def print_py(self): """ Return the list of interfaces. diff --git a/bindings/python_cffi/czmq_cffi/cdefs.py b/bindings/python_cffi/czmq_cffi/cdefs.py index f7564d5c6..55c5879f0 100644 --- a/bindings/python_cffi/czmq_cffi/cdefs.py +++ b/bindings/python_cffi/czmq_cffi/cdefs.py @@ -1627,6 +1627,10 @@ const char * ziflist_netmask (ziflist_t *self); +// Return the current interface MAC address as a printable string +const char * + ziflist_mac (ziflist_t *self); + // Return the list of interfaces. void ziflist_print (ziflist_t *self); diff --git a/bindings/qml/src/QmlZiflist.cpp b/bindings/qml/src/QmlZiflist.cpp index 8af486ba7..7d90c3e84 100644 --- a/bindings/qml/src/QmlZiflist.cpp +++ b/bindings/qml/src/QmlZiflist.cpp @@ -50,6 +50,12 @@ const QString QmlZiflist::netmask () { return QString (ziflist_netmask (self)); }; +/// +// Return the current interface MAC address as a printable string +const QString QmlZiflist::mac () { + return QString (ziflist_mac (self)); +}; + /// // Return the list of interfaces. void QmlZiflist::print () { diff --git a/bindings/qml/src/QmlZiflist.h b/bindings/qml/src/QmlZiflist.h index 3fa015d7f..4b69b6845 100644 --- a/bindings/qml/src/QmlZiflist.h +++ b/bindings/qml/src/QmlZiflist.h @@ -49,6 +49,9 @@ public slots: // Return the current interface network mask as a printable string const QString netmask (); + // Return the current interface MAC address as a printable string + const QString mac (); + // Return the list of interfaces. void print (); diff --git a/bindings/qt/src/qziflist.cpp b/bindings/qt/src/qziflist.cpp index 0ef03f52c..6039351dd 100644 --- a/bindings/qt/src/qziflist.cpp +++ b/bindings/qt/src/qziflist.cpp @@ -85,6 +85,14 @@ const QString QZiflist::netmask () return rv; } +/// +// Return the current interface MAC address as a printable string +const QString QZiflist::mac () +{ + const QString rv = QString (ziflist_mac (self)); + return rv; +} + /// // Return the list of interfaces. void QZiflist::print () diff --git a/bindings/qt/src/qziflist.h b/bindings/qt/src/qziflist.h index 40d2bce36..8be08ec76 100644 --- a/bindings/qt/src/qziflist.h +++ b/bindings/qt/src/qziflist.h @@ -44,6 +44,9 @@ class QT_CZMQ_EXPORT QZiflist : public QObject // Return the current interface network mask as a printable string const QString netmask (); + // Return the current interface MAC address as a printable string + const QString mac (); + // Return the list of interfaces. void print (); diff --git a/bindings/ruby/lib/czmq/ffi.rb b/bindings/ruby/lib/czmq/ffi.rb index e6678cece..22d443ba0 100644 --- a/bindings/ruby/lib/czmq/ffi.rb +++ b/bindings/ruby/lib/czmq/ffi.rb @@ -383,6 +383,7 @@ def self.attach_function(name, *rest) attach_function :ziflist_address, [:pointer], :string, **opts attach_function :ziflist_broadcast, [:pointer], :string, **opts attach_function :ziflist_netmask, [:pointer], :string, **opts + attach_function :ziflist_mac, [:pointer], :string, **opts attach_function :ziflist_print, [:pointer], :void, **opts attach_function :ziflist_new_ipv6, [], :pointer, **opts attach_function :ziflist_reload_ipv6, [:pointer], :void, **opts diff --git a/bindings/ruby/lib/czmq/ffi/ziflist.rb b/bindings/ruby/lib/czmq/ffi/ziflist.rb index cce509853..96c9250e6 100644 --- a/bindings/ruby/lib/czmq/ffi/ziflist.rb +++ b/bindings/ruby/lib/czmq/ffi/ziflist.rb @@ -160,6 +160,16 @@ def netmask() result end + # Return the current interface MAC address as a printable string + # + # @return [String] + def mac() + raise DestroyedError unless @ptr + self_p = @ptr + result = ::CZMQ::FFI.ziflist_mac(self_p) + result + end + # Return the list of interfaces. # # @return [void] diff --git a/include/czmq_prelude.h b/include/czmq_prelude.h index 785ae052b..d320114df 100644 --- a/include/czmq_prelude.h +++ b/include/czmq_prelude.h @@ -327,6 +327,15 @@ # if (defined (__UTYPE_LINUX) && defined (HAVE_LIBSYSTEMD)) # include # endif +# if (defined (HAVE_GETIFADDRS)) +# if (defined (__UTYPE_OSX)) +# include // For struct sockaddr_dl +# include +# include +# else +# include // For struct sockaddr_ll +# endif +# endif #endif #if (defined (__VMS__)) diff --git a/include/ziflist.h b/include/ziflist.h index b056e4d33..0224a2f0b 100644 --- a/include/ziflist.h +++ b/include/ziflist.h @@ -70,6 +70,11 @@ CZMQ_EXPORT void ziflist_test (bool verbose); #ifdef CZMQ_BUILD_DRAFT_API +// *** Draft method, for development use, may change without warning *** +// Return the current interface MAC address as a printable string +CZMQ_EXPORT const char * + ziflist_mac (ziflist_t *self); + // *** Draft method, for development use, may change without warning *** // Get a list of network interfaces currently defined on the system // Includes IPv6 interfaces diff --git a/src/czmq_classes.h b/src/czmq_classes.h index 080cebca0..19bcec578 100644 --- a/src/czmq_classes.h +++ b/src/czmq_classes.h @@ -212,6 +212,11 @@ CZMQ_PRIVATE zframe_t * CZMQ_PRIVATE zhashx_t * zhashx_unpack_own (zframe_t *frame, zhashx_deserializer_fn deserializer); +// *** Draft method, defined for internal use only *** +// Return the current interface MAC address as a printable string +CZMQ_PRIVATE const char * + ziflist_mac (ziflist_t *self); + // *** Draft method, defined for internal use only *** // Get a list of network interfaces currently defined on the system // Includes IPv6 interfaces diff --git a/src/ziflist.c b/src/ziflist.c index ba437b286..a52a5dfb1 100644 --- a/src/ziflist.c +++ b/src/ziflist.c @@ -30,6 +30,7 @@ typedef struct { char *address; char *netmask; char *broadcast; + char *mac; bool is_ipv6; } interface_t; @@ -47,6 +48,7 @@ s_interface_destroy (interface_t **self_p) freen (self->address); freen (self->netmask); freen (self->broadcast); + freen (self->mac); freen (self); *self_p = NULL; } @@ -58,7 +60,7 @@ s_interface_destroy (interface_t **self_p) static interface_t * s_interface_new (char *name, struct sockaddr *address, struct sockaddr *netmask, - struct sockaddr *broadcast) + struct sockaddr *broadcast, const char *mac) { char hbuf[NI_MAXHOST]; int rc; @@ -109,6 +111,8 @@ s_interface_new (char *name, struct sockaddr *address, struct sockaddr *netmask, assert (self->broadcast); } + self->mac = strdup(mac); + self->is_ipv6 = address->sa_family == AF_INET6 ? true : false; return self; @@ -159,6 +163,7 @@ ziflist_print (ziflist_t *self) zsys_info (" - interface address : %s", iface->address); zsys_info (" - interface netmask : %s", iface->netmask); zsys_info (" - interface broadcast : %s", iface->broadcast); + zsys_info (" - interface mac : %s", iface->mac); } } @@ -206,7 +211,42 @@ s_reload (ziflist_t *self, bool ipv6) struct ifaddrs *interfaces; if (getifaddrs (&interfaces) == 0) { struct ifaddrs *interface = interfaces; + zhash_t *mactable = zhash_new(); + zhash_autofree(mactable); while (interface) { + // first try to get a mac addr and save it in a table +#if defined __UTYPE_OSX + if (interface->ifa_addr != NULL && interface->ifa_flags & IFF_UP && interface->ifa_addr->sa_family == AF_LINK) + { + struct sockaddr_dl *sdl = (struct sockaddr_dl *) interface->ifa_addr; + if (sdl->sdl_type == IFT_ETHER) + { + const unsigned char *rawmac = (unsigned char *)sdl->sdl_data + sdl->sdl_nlen; + char mac[18] = "NA"; + int i; + int len = 0; + for (i = 0; i < 6; i++) + { + len += snprintf(mac+len, 18, "%02X%s", rawmac[i], i < 5 ? ":":""); + } + zhash_insert(mactable, interface->ifa_name, (void *)mac); + } + } +#else + if (interface->ifa_addr && ((interface)->ifa_addr)->sa_family == AF_PACKET) + { + unsigned char mac[18] = "NA"; + struct sockaddr_ll *s = (struct sockaddr_ll*)(interface->ifa_addr); + int i; + int len = 0; + for (i = 0; i < 6; i++) { + len += snprintf(mac+len, 18, "%02X%s", s->sll_addr[i], i < 5 ? ":":""); + } + zhash_insert(mactable, (interface)->ifa_name, (void *)mac); + } +#endif + // next get layer 3 info if any + // On Solaris, loopback interfaces have a NULL in ifa_broadaddr if (interface->ifa_addr && (interface->ifa_broadaddr @@ -217,15 +257,18 @@ s_reload (ziflist_t *self, bool ipv6) &&(interface->ifa_netmask->sa_family == AF_INET || (ipv6 && (interface->ifa_netmask->sa_family == AF_INET6))) && s_valid_flags (interface->ifa_flags, - ipv6 && (interface->ifa_addr->sa_family == AF_INET6))) { + ipv6 && (interface->ifa_addr->sa_family == AF_INET6))) + { + const char *mac = zhash_lookup(mactable, interface->ifa_name); interface_t *item = s_interface_new (interface->ifa_name, interface->ifa_addr, interface->ifa_netmask, - interface->ifa_broadaddr); + interface->ifa_broadaddr, mac); if (item) zlistx_add_end (list, item); } interface = interface->ifa_next; } + zhash_destroy(&mactable); } freeifaddrs (interfaces); @@ -269,10 +312,20 @@ s_reload (ziflist_t *self, bool ipv6) else is_valid = false; + unsigned char mac[18] = "NA"; + unsigned char rawmac[6]; + if (!ioctl(sock, SIOCGIFHWADDR, (caddr_t)ifr, sizeof(struct ifreq))) { + memcpy(rawmac, ifr->ifr_hwaddr.sa_data, 6); + int len = 0; + for (int i = 0; i < 6; i++) { + len += snprintf(mac+len, 18, "%02X%s", rawmac[i], i < 5 ? ":":"" ); + } + } + if (is_valid) { interface_t *item = s_interface_new (ifr->ifr_name, (struct sockaddr *)&address, (struct sockaddr *)&netmask, - (struct sockaddr *)&broadcast); + (struct sockaddr *)&broadcast, mac); if (item) zlistx_add_end (list, item); } @@ -334,9 +387,19 @@ s_reload (ziflist_t *self, bool ipv6) netmask.sin_family = AF_INET; broadcast = address; broadcast.sin_addr.s_addr |= ~(netmask.sin_addr.s_addr); + // Retrieve the MAC address from the PIP_ADAPTER_ADDRESSES structure + unsigned char *mac_address = cur_address->PhysicalAddress; + char mac[18] = "NA"; + if (mac_address != NULL && cur_address->PhysicalAddressLength == 6) { + int len = 0; + for (int i = 0; i < 6; i++) { + len += snprintf( mac+len, 18, "%02X%s", mac_address[i], i < 5 ? ":":"" ); + } + } interface_t *item = s_interface_new (asciiFriendlyName, (struct sockaddr *)&address, (struct sockaddr *)&netmask, - (struct sockaddr *)&broadcast); + (struct sockaddr *)&broadcast, mac); + if (item) zlistx_add_end (list, item); } @@ -456,6 +519,16 @@ ziflist_netmask (ziflist_t *self) return NULL; } +const char * +ziflist_mac (ziflist_t *self) +{ + assert (self); + interface_t *iface = (interface_t *) zlistx_item ((zlistx_t *) self); + if (iface) + return iface->mac; + else + return NULL; +} // -------------------------------------------------------------------------- // Return true if the current interface uses IPv6 @@ -494,13 +567,28 @@ ziflist_test (bool verbose) assert (iflist); size_t items = ziflist_size (iflist); + if (items) + { + // test mac addresses + const char *item = ziflist_first(iflist); + while (item) + { + const char *mac = ziflist_mac(iflist); + if ( strlen(mac) == 17 ) + assert( mac[2] == ':' && mac[5] == ':' && mac[8] == ':' + && mac[11] == ':' && mac[14] == ':' ); + else + assert( strlen(mac) == 2 ); + item = ziflist_next (iflist); + } + } if (verbose) { printf ("ziflist: interfaces=%zu\n", ziflist_size (iflist)); const char *name = ziflist_first (iflist); while (name) { - printf (" - name=%s address=%s netmask=%s broadcast=%s\n", - name, ziflist_address (iflist), ziflist_netmask (iflist), ziflist_broadcast (iflist)); + printf (" - name=%s address=%s netmask=%s broadcast=%s mac=%s\n", + name, ziflist_address (iflist), ziflist_netmask (iflist), ziflist_broadcast (iflist), ziflist_mac(iflist)); name = ziflist_next (iflist); } }