2

サーバーのすべての要求であるクライアントの MAC アドレスを取得したいと考えています。次のプログラムを使用してクライアントの MAC アドレスを取得しますが、「ioctl: Protocol Family Not Supported」と表示されます。MACアドレスを取得するにはどうすればよいですか? ...

#include<stdio.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<netdb.h>
#include<errno.h>
#include<string.h>
#include<netinet/if_ether.h>
#include<net/if.h>
#include<linux/sockios.h>
int main()
{
  int socket1, socket2;
  socket1 = 0;
  socket2 = 0;
  struct sockaddr_in server, client;
  int returnstatus = 0;
socket1 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(socket1 == -1)
{
  perror("socket()");
}

server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(8888);
returnstatus = bind(socket1, (struct sockaddr*)&server, sizeof(server));
if(returnstatus == -1)
{
  perror("bind()");
}
returnstatus = listen(socket1, 5);
if(returnstatus == -1)
{
 perror("listen()");
}
for(;;)
{
  int buffr[4];
  int addrlen, n;
  addrlen = sizeof(client);
  socket2 = accept(socket1, (struct sockaddr *)&client, &addrlen);
    printf("%s\n",inet_ntoa(client.sin_addr));
    printf("%d\n",(int) ntohs(client.sin_port));
struct arpreq arpreq_;
bzero(&arpreq_, sizeof(struct arpreq));

if( ( n = ioctl(socket2, SIOCGARP, &arpreq_) ) < 0 ){
perror("ioctl");
}

unsigned char *ptr = &arpreq_.arp_ha.sa_data[0];
printf("MAC: %x:%x:%x:%x:%x:%x\n", *ptr, *(ptr+1), *(ptr+2), *(ptr+3),
*(ptr+4), *(ptr+5));

if (socket2 == -1)
{
  perror("accept()");
}
returnstatus = read(socket2, buffr, sizeof(buffr));

if(returnstatus == -1)
{
  perror("read()");
}
int c[2]; 
int *w;
c[0] = buffr[0] + buffr[1];
w = c;
returnstatus = write(socket2, w, sizeof(c));
if(returnstatus == -1)
{
 perror("write()");
}
close(socket2);

}
close(socket1);
return 0;
}

int addition(int x, int y)
{
 int z;
 z = x + y;
 return(z);
}
4

2 に答える 2

3

私はあなたが望むことをするように見えるいくつかのコードを持っています。

ネットワーク上のリモート コンピューターから 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;
}
于 2016-04-02T01:35:41.867 に答える
1

SIOCGARPioctl(SIOCGARP)はローカル ARP テーブルから MAC アドレスを返すため、ローカル サブネットの MAC アドレスのみを取得できます。

SIOCGARP少し間違った方法を使用しています。SIOCGARP の引数は入出力型です。arpreq_したがって、を呼び出す前にのいくつかのフィールドに入力する必要がありますioctlマニュアルページを参照してください。

ピアがイーサネット サブネットの外にある場合、トラフィックはルーターを経由し、ピアはイーサネット ネットワーク内にあるかどうかに関係なく (例: 携帯電話)。そのため、すべてのピアからイーサネット MAC アドレスを取得することは不可能な場合があります。

ホストがピアと通信する場合、最初のルーターの MAC アドレスが使用されます。

于 2012-08-17T18:38:12.900 に答える