GNU/Linux >> Belajar Linux >  >> Linux

Linux:Ikat soket pendengar UDP ke antarmuka tertentu (atau temukan antarmuka asal datagram)?

Solusi yang saya temukan berhasil adalah sebagai berikut. Pertama-tama, kita harus mengubah pengaturan ARP dan RP. Ke /etc/sysctl.conf, tambahkan yang berikut dan reboot (ada juga perintah untuk mengatur ini secara dinamis):

net.ipv4.conf.default.arp_filter = 1
net.ipv4.conf.default.rp_filter = 2
net.ipv4.conf.all.arp_filter = 1
net.ipv4.conf.all.rp_filter = 2

Filter arp diperlukan untuk mengizinkan respons dari eth0 ke rute melalui WAN. Opsi filter rp diperlukan untuk secara ketat mengaitkan paket yang masuk dengan NIC tempat mereka masuk (berlawanan dengan model lemah yang mengaitkannya dengan NIC apa pun yang cocok dengan subnet). Komentar dari EJP mengarahkan saya ke langkah kritis ini.

Setelah itu, SO_BINDTODEVICE mulai bekerja. Masing-masing dari dua soket terikat ke NIC-nya sendiri, dan oleh karena itu saya dapat mengetahui dari NIC mana pesan berasal berdasarkan soket asalnya.

s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
rc=setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, nic, IF_NAMESIZE);
memset((char *) &si_me, 0, sizeof(si_me));
si_me.sin_family = AF_INET;
si_me.sin_port = htons(LISTEN_PORT);
si_me.sin_addr.s_addr = htonl(INADDR_ANY);
rc=bind(s, (struct sockaddr *)&si_me, sizeof(si_me))

Selanjutnya, saya ingin menanggapi datagram yang masuk dengan datagram yang alamat sumbernya adalah dari NIC asal permintaan asli. Jawabannya adalah dengan mencari alamat NIC itu dan mengikat soket keluar ke alamat itu (menggunakan bind ).

s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
get_nic_addr(nics, (struct sockaddr *)&sa)
sa.sin_port = 0;
rc = bind(s, (struct sockaddr *)&sa, sizeof(struct sockaddr));
sendto(s, ...);

int get_nic_addr(const char *nic, struct sockaddr *sa)
{
    struct ifreq ifr;
    int fd, r;
    fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (fd < 0) return -1;
    ifr.ifr_addr.sa_family = AF_INET;
    strncpy(ifr.ifr_name, nic, IFNAMSIZ);
    r = ioctl(fd, SIOCGIFADDR, &ifr);
    if (r < 0) { ... }
    close(fd);
    *sa = *(struct sockaddr *)&ifr.ifr_addr;
    return 0;
}

(Mungkin mencari alamat NIC setiap saat sepertinya sia-sia, tetapi itu jauh lebih banyak kode untuk mendapatkan informasi ketika alamat berubah, dan transaksi ini terjadi hanya sekali setiap beberapa detik pada sistem yang tidak menggunakan baterai.)


Anda bisa mendapatkan alamat tujuan yang digunakan oleh pengirim melalui IP_RECVDSTADDR opsi jika platform Anda mendukungnya, dengan menggunakan recvmsg() . Ini agak rumit, dijelaskan di Pemrograman Jaringan Unix, jilid I, edisi ke-3, #22.2, dan di man halaman.

Jika Anda mengedit, Anda menghadapi apa yang dikenal sebagai 'model sistem ujung lemah' dari TCP/IP. Pada dasarnya setelah sebuah paket tiba, sistem dapat memilih untuk mengirimkannya melalui antarmuka yang sesuai dengan mendengarkan port yang benar. Ini dibahas di RFC TCP/IP di suatu tempat.


Anda memberikan nilai ilegal ke setsockopt .

rc=setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, nic, strlen(nic));

Halaman manual mengatakan tentang SO_BIND_TO_DEVICE :

Opsi yang diteruskan adalah panjang variabel dihentikan dengan nol string nama antarmuka dengan ukuran maksimum IFNAMSIZ

strlen tidak termasuk null terminasi. Anda dapat mencoba:

rc=setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, nic, 1 + strlen(nic));

dnsmasq apakah ini berfungsi dengan benar, dan menggunakan

setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, intname, IF_NAMESIZE)

Linux
  1. Linux – Bagaimana Cara Mengetahui Hard Disk Apa yang Ada di Sistem?

  2. Bagaimana saya bisa menemukan file tertentu dari terminal Linux?

  3. Bagaimana cara mengirim pesan ke soket web socket.io saya dari baris perintah di linux?

  1. Linux:cari tahu proses apa yang menggunakan semua RAM?

  2. Bagaimana cara mengetahui antarmuka mana yang saya gunakan untuk terhubung ke internet?

  3. Cara menjalankan TeX dari antarmuka baris perintah di Linux

  1. Cara Menemukan Paket Yang Menyediakan File Tertentu Di Linux

  2. Cari tahu server DNS untuk koneksi DHCP di Linux

  3. Bagaimana cara mengetahui jenis virtualisasi VPS linux?