LINUX.ORG.RU

Как вытянуть MAC-адресс из сокета?


0

0

Собственно вопрос: в ядре есть системный вызов accept4(), он возвращает структуру sockaddr, соодержащую IP и порт, а мне надо изменить эту структуру и сам системный вызов, чтоб в нее еще добалялся MAC-адресс. Насколько я понимаю надо работать с RAW сокетом, но вот как все это реализовать?



Последнее исправление: savgur (всего исправлений: 2)

Ты хочешь узнать mac адрес компа, с которого пришел пакет? Это возможно? А то недавно на одном форуме модер грозился забанить по мак-адресу, а я думал что это невозможно.

anonymous
()
Ответ на: комментарий от anonymous

В локалке возможно. Между сетями MAC не пересылается.
Модер тебя на понт взял :)

power
()

>надо изменить эту структуру и сам системный вызов
Не.

надо работать с RAW сокетом

Да, мой пост выше. Ещё поковыряй Wireshark, packETH.

anon_666
()

>RAW сокетом, но вот как все это реализовать

Сделай библиотеку, кот-я будет перехватывать socket() и тд, обрабатывать и далее слать через raw, потом загружай через LD_PRELOAD=.

anon_666
()

а мне надо изменить эту структуру и сам системный вызов, чтоб в нее еще добалялся MAC-адресс


Ты хоть понял сам что тебе нужно?! Если тебе нужно узнать мак, создай арп-струкуру заполни ее и отсылай в ответ получишь свой мак. Почитай про канальный уровень.
Если хочешь все в одной структуре, создай просто структуру состоящую из структур: арп и сокета, и с ней работай.

Boy_from_Jungle ★★★★
()

>Насколько я понимаю надо работать с RAW сокетом

тебе нужно поработать над пониманием модели OSI

Deleted
()
fantom@ghost:/tmp$ cat >mac.c
#include <stdio.h>

#include <string.h> /* for strncpy */

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>

int
main()
{
 int fd;
 struct ifreq ifr;

 fd = socket(AF_INET, SOCK_DGRAM, 0);

 ifr.ifr_addr.sa_family = AF_INET;
 strncpy(ifr.ifr_name, "eth0", IFNAMSIZ-1);

 ioctl(fd, SIOCGIFHWADDR, &ifr);

 close(fd);

 /* display result */
 printf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
         (unsigned char)ifr.ifr_hwaddr.sa_data[0],
         (unsigned char)ifr.ifr_hwaddr.sa_data[1],
         (unsigned char)ifr.ifr_hwaddr.sa_data[2],
         (unsigned char)ifr.ifr_hwaddr.sa_data[3],
         (unsigned char)ifr.ifr_hwaddr.sa_data[4],
         (unsigned char)ifr.ifr_hwaddr.sa_data[5]);

 return 0;
}
^C
fantom@ghost:/tmp$ gcc -o mac ./mac.c 
fantom@ghost:/tmp$ ./mac 
6c:f0:49:5e:4d:91
Deleted
()

Учи TCP/IP, ты не можешь узнать mac адрес удаленного компа, если только ты не создашь свой протокол уровня данных и не будешь передавать мак-адрес в блоке данных, но тогда ты сам будешь знать как это сделать=)

Dudraug ★★★★★
()
Ответ на: комментарий от anon_666

mac меняется программно, это даже для локалки не страшно.

Если только в локалке нет ограничений на маки=)

Dudraug ★★★★★
()
Ответ на: комментарий от Dudraug

Согласен, плохо сформулировал задачу: в системном вызове ядра accept4 кроме IP адреса и порта удаленной машины нужно уметь считать MAC адрес интерфейса на который поступило соединение. Например если интерфейса два и более.

savgur
() автор топика
Ответ на: комментарий от savgur

наводящий вопрос:

А если у тебя не езернет а допустим ппп через ком порт с модемом? Как будешь мак адрес извлекать?

nanoo_linux
()

мак адрес всегда будет ближайшего роутера, если только его кто-то не поменяет

dimon555 ★★★★★
()

man 7 packet

socket(PF_INET, SOCK_RAW, ...) даст сырой доступ только к данным, начиная с L3-заголовка, то есть IP. В буфере данных увидишь struct iphdr, или как её там...

Чтоб вот прямо с L2 (эзернетом) надо использовать пакетные сокеты (субж). Что-то вроде:

socket(AF_PACKET, int socket_type, htons(ETH_P_IP));
Правда тут в сокет будет валиться ВЕСЬ IP-траффик. Возможно получится отфильтровать нужный через:

setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)), где а ifr.ifr_name имя ифейса, но это не то, так как по условиям задачи ифейсов много.

и/или забиндить на нужный адрес:порт (man 2 bind), но тут не уверен прокатит ли такое для пакетного сокета. Как-то сомневаюсь.

А 100% вариант фильтрации нужного трафа - это на пакетный сокет навешать фильтров как это делает libpcap. В сокет будет как в tcpdump отлавливать только нужные пакетики, но
1. Придётся осваивать такие bpf-фильтры. В стандартных манах нет.
2. Таки распарсивать пакет на заголовки: sockaddr_ll, IP, TCP/UDP, собсно данные.


farisey
()
Ответ на: man 7 packet от farisey

>Чтоб вот прямо с L2 (эзернетом) надо использовать пакетные сокеты >(субж). Что-то вроде:

socket(AF_PACKET, int socket_type, htons(ETH_P_IP));

Это да, но как я получу такой сокет? В sys_accept4() первый аргумент - файловый дескриптор, его надо в пакетный сокет преобразовать что-ли?

savgur
() автор топика
Ответ на: комментарий от savgur

Вот кстати код для наглядности:

/*
 *	For accept, we attempt to create a new socket, set up the link
 *	with the client, wake up the client, then return the new
 *	connected fd. We collect the address of the connector in kernel
 *	space and move it to user at the very end. This is unclean because
 *	we open the socket then return an error.
 *
 *	1003.1g adds the ability to recvmsg() to query connection pending
 *	status to recvmsg. We need to add that support in a way thats
 *	clean when we restucture accept also.
 */

asmlinkage long sys_accept4(int fd, struct sockaddr __user *upeer_sockaddr,
			    int __user *upeer_addrlen, int flags)
{
	struct socket *sock, *newsock;
	struct file *newfile;
	int err, len, newfd, fput_needed;
	struct sockaddr_storage address;

	if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
		return -EINVAL;

	if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK))
		flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK;

	sock = sockfd_lookup_light(fd, &err, &fput_needed);
	if (!sock)
		goto out;

	err = -ENFILE;
	if (!(newsock = sock_alloc()))
		goto out_put;

	newsock->type = sock->type;
	newsock->ops = sock->ops;

	/*
	 * We don't need try_module_get here, as the listening socket (sock)
	 * has the protocol module (sock->ops->owner) held.
	 */
	__module_get(newsock->ops->owner);

	newfd = sock_alloc_fd(&newfile, flags & O_CLOEXEC);
	if (unlikely(newfd < 0)) {
		err = newfd;
		sock_release(newsock);
		goto out_put;
	}

	err = sock_attach_fd(newsock, newfile, flags & O_NONBLOCK);
	if (err < 0)
		goto out_fd_simple;

	err = security_socket_accept(sock, newsock);
	if (err)
		goto out_fd;

	err = sock->ops->accept(sock, newsock, sock->file->f_flags);
	if (err < 0)
		goto out_fd;

	if (upeer_sockaddr) {
		if (newsock->ops->getname(newsock, (struct sockaddr *)&address,
					  &len, 2) < 0) {
			err = -ECONNABORTED;
			goto out_fd;
		}
		err = move_addr_to_user((struct sockaddr *)&address,
					len, upeer_sockaddr, upeer_addrlen);
		if (err < 0)
			goto out_fd;
	}

	/* File flags are not inherited via accept() unlike another OSes. */

	fd_install(newfd, newfile);
	err = newfd;

	security_socket_post_accept(sock, newsock);

out_put:
	fput_light(sock->file, fput_needed);
out:
	return err;
out_fd_simple:
	sock_release(newsock);
	put_filp(newfile);
	put_unused_fd(newfd);
	goto out_put;
out_fd:
	fput(newfile);
	put_unused_fd(newfd);
	goto out_put;
}

savgur
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.