私はあなたが望むことをするように見えるいくつかのコードを持っています。
ネットワーク上のリモート コンピューターから MAC アドレスを取得する C++ コードを取得しようとしています。これを理解するのにかなりの時間がかかりました。いくつかの例を実際のデモにマージして変更することができました。これをソケット接続で動作するように変更するのは非常に簡単です。
このコードは、ネットワーク デバイスと IP アドレスを引数として受け取ります。(例: eth0 192.168.1.1)
プログラムは IP の正確性をチェックし、IP アドレスを ping して ARP テーブルに追加し、ARP テーブルから MAC アドレスを抽出して、MAC アドレスを表示します。
私は C++ コーダーではない (または少なくとも私は newb です) ので、コードはおそらくブラッシュアップされる可能性があります。
このコードは Raspbian でのみテストされています!
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if_arp.h>
#include <arpa/inet.h>
#include <sstream>
bool isValidIpAddress(char *ipAddress) {
int result = 0;
struct sockaddr_in sa;
result = inet_pton(AF_INET, ipAddress, &(sa.sin_addr));
return result;
}
/**
* @brief Convert String to Number
*/
template <typename TP>
TP str2num( std::string const& value ){
std::stringstream sin;
sin << value;
TP output;
sin >> output;
return output;
}
/**
* @brief Convert number to string
*/
template <typename TP>
std::string num2str( TP const& value ){
std::stringstream sin;
sin << value;
return sin.str();
}
/**
* @brief Execute Generic Shell Command
*
* @param[in] command Command to execute.
* @param[out] output Shell output.
* @param[in] mode read/write access
*
* @return 0 for success, 1 otherwise.
*
*/
int Execute_Command( const std::string& command,
std::string& output,
const std::string& mode = "r") {
// Create the stringstream
std::stringstream sout;
// Run Popen
FILE *in;
char buff[512];
// Test output
if(!(in = popen(command.c_str(), mode.c_str()))){
return 1;
}
// Parse output
while(fgets(buff, sizeof(buff), in)!=NULL){
sout << buff;
}
// Close
int exit_code = pclose(in);
// set output
output = sout.str();
// Return exit code
return exit_code;
}
/**
* @brief Ping
*
* @param[in] address Address to ping.
* @param[in] max_attempts Number of attempts to try and ping.
* @param[out] details Details of failure if one occurs.
*
* @return True if responsive, false otherwise.
*
* @note { I am redirecting stderr to stdout. I would recommend
* capturing this information separately.}
*/
bool Ping( const std::string& address ) {
// Format a command string
std::string command = "ping -c " + num2str(2) + " " + address + " 2>&1";
std::string output;
std::string details;
// Execute the ping command
int code = Execute_Command( command, details );
return (code == 0);
}
static char *ethernet_mactoa(struct sockaddr *addr) {
static char buff[256];
unsigned char *ptr = (unsigned char *) addr->sa_data;
sprintf(buff, "%02X:%02X:%02X:%02X:%02X:%02X",
(ptr[0] & 0xff), (ptr[1] & 0xff), (ptr[2] & 0xff),
(ptr[3] & 0xff), (ptr[4] & 0xff), (ptr[5] & 0xff));
return (buff);
}
int main(int argc, char *argv[]) {
int s;
struct arpreq areq;
struct sockaddr_in *sin;
struct in_addr ipaddr;
if (argc != 3) {
fprintf(stderr, "-- Usage: %s device ipaddress\n", argv[0]);
exit(1);
}
/* Get an internet domain socket. */
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
perror("socket");
exit(1);
}
if (!isValidIpAddress(argv[2])) {
fprintf(stderr, "-- Error: invalid IP Address '%s'.\n",
argv[2]);
exit(1);
}
if (inet_aton(argv[2], &ipaddr) == 0) {
fprintf(stderr, "-- Error: bad dotted-decimal IP '%s'.\n",
argv[2]);
exit(1);
}
/* Ping the Address for ARP table listing */
if ( !Ping(argv[2]) ) {
fprintf(stderr, "-- Error: unable to ping IP '%s'.\n",
argv[2]);
exit(1);
}
/* Make the ARP request. */
memset(&areq, 0, sizeof(areq));
sin = (struct sockaddr_in *) &areq.arp_pa;
sin->sin_family = AF_INET;
sin->sin_addr = ipaddr;
sin = (struct sockaddr_in *) &areq.arp_ha;
sin->sin_family = ARPHRD_ETHER;
strncpy(areq.arp_dev, argv[1], 15);
if (ioctl(s, SIOCGARP, (caddr_t) &areq) == -1) {
perror("-- Error: unable to make ARP request, error");
exit(1);
}
printf("%s -> %s\n",
inet_ntoa(((struct sockaddr_in *) &areq.arp_pa)->sin_addr),
ethernet_mactoa(&areq.arp_ha));
return 0;
}