|
|
1.1 ! root 1: // ! 2: // nono ! 3: // Copyright (C) 2021 nono project ! 4: // Licensed under nono-license.txt ! 5: // ! 6: ! 7: // AF_PACKET を用いたドライバ ! 8: // Linux 2.2 以降専用 ! 9: ! 10: #include "netdriver_afpacket.h" ! 11: #include "autofd.h" ! 12: #include <ifaddrs.h> ! 13: #include <sys/socket.h> ! 14: #include <sys/ioctl.h> ! 15: #include <net/if.h> ! 16: #include <net/if_arp.h> ! 17: ! 18: // コンストラクタ ! 19: NetDriverAFPacket::NetDriverAFPacket(EthernetDevice *parent_, int loglevel_, ! 20: const std::string& ifname_) ! 21: : inherited("AFPacket", parent_, loglevel_) ! 22: { ! 23: ifname = ifname_; ! 24: if (ifname.empty()) { ! 25: ifname = "auto"; ! 26: } ! 27: } ! 28: ! 29: // デストラクタ ! 30: NetDriverAFPacket::~NetDriverAFPacket() ! 31: { ! 32: Close(); ! 33: } ! 34: ! 35: // ドライバ初期化 & オープン ! 36: bool ! 37: NetDriverAFPacket::InitDriver() ! 38: { ! 39: packet_mreq mreq {}; ! 40: int len; ! 41: socklen_t so_len; ! 42: ! 43: putmsg(1, "trying afpacket..."); ! 44: putmsg(1, "argument: ifname=\"%s\"", ifname.c_str()); ! 45: ! 46: sll.sll_family = AF_PACKET; ! 47: sll.sll_protocol = htons(ETH_P_ALL); ! 48: sll.sll_ifindex = SelectInterface(); ! 49: if (sll.sll_ifindex == 0) { ! 50: goto abort; ! 51: } ! 52: ! 53: // bind するまでの期間、このソケットにはシステムのすべての ! 54: // インタフェースからのパケットが着信することに注意。 ! 55: fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); ! 56: if (fd < 0) { ! 57: errmsg = string_format("%s: %s", "socket(AF_PACKET)", strerror(errno)); ! 58: putmsg(1, "%s", errmsg.c_str()); ! 59: if (errno == EPERM) { ! 60: // Linux では setcap(8) が必要。分かりづらいのでメッセージを出すが ! 61: // その例示より先に errmsg を表示したい。 ! 62: warnx("%s", errmsg.c_str()); ! 63: errmsg.clear(); ! 64: ! 65: fprintf(stderr, ! 66: " ** Set CAP_NET_RAW capability to the nono executable file.\n" ! 67: " ** ex) sudo setcap cap_net_raw=ep path/to/%s\n", ! 68: getprogname()); ! 69: } ! 70: return false; ! 71: } ! 72: ! 73: if (bind(fd, (const sockaddr *)&sll, sizeof(sll)) != 0) { ! 74: errmsg = string_format("bind(%s): %s", ifname.c_str(), strerror(errno)); ! 75: goto abort; ! 76: } ! 77: ! 78: // PROMISC セット ! 79: mreq.mr_ifindex = sll.sll_ifindex; ! 80: mreq.mr_type = PACKET_MR_PROMISC; ! 81: if (setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, ! 82: &mreq, sizeof(mreq)) != 0) { ! 83: errmsg = string_format("%s: %s", "set PROMISC", strerror(errno)); ! 84: goto abort; ! 85: } ! 86: ! 87: so_len = sizeof(len); ! 88: if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &len, &so_len) != 0) { ! 89: errmsg = string_format("%s: %s", ! 90: "getsockopt(SO_RCVBUF)", strerror(errno)); ! 91: goto abort; ! 92: } ! 93: ! 94: putmsg(1, "opened for %s", ifname.c_str()); ! 95: putmsg(1, "warning: communicating with the localhost is not possible"); ! 96: ! 97: // AFPacket では ifup スクリプトは実行しない ! 98: ! 99: return true; ! 100: ! 101: abort: ! 102: putmsg(1, "%s", errmsg.c_str()); ! 103: Close(); ! 104: return false; ! 105: } ! 106: ! 107: // クローズ ! 108: // (private) ! 109: void ! 110: NetDriverAFPacket::Close() ! 111: { ! 112: if (IsOpen()) { ! 113: close(fd); ! 114: fd = -1; ! 115: } ! 116: } ! 117: ! 118: // モニタ (ドライバ依存情報のみ) ! 119: void ! 120: NetDriverAFPacket::MonitorUpdateMD(TextScreen& screen) ! 121: { ! 122: screen.Print(0, 1, "Interface: %s", ifname.c_str()); ! 123: } ! 124: ! 125: // パケットを送信する ! 126: bool ! 127: NetDriverAFPacket::SendPacket(const std::vector<uint8>& data) ! 128: { ! 129: int n; ! 130: ! 131: assert(IsOpen()); ! 132: ! 133: putlog(2, "SendPacket %zu bytes", data.size()); ! 134: tx_pkts++; ! 135: tx_bytes += data.size(); ! 136: ! 137: n = sendto(fd, data.data(), data.size(), 0, ! 138: (const sockaddr *)&sll, sizeof(sll)); ! 139: if (n == -1) { ! 140: warn("NetDriverAFPacket.SendPacket: sendto failed: fd=%d datalen=%zu", ! 141: fd, data.size()); ! 142: return false; ! 143: } ! 144: ! 145: if (n < (int)data.size()) { ! 146: return false; ! 147: } ! 148: return true; ! 149: } ! 150: ! 151: // パケットを受信する ! 152: ssize_t ! 153: NetDriverAFPacket::RecvPacket() ! 154: { ! 155: uint8 buf[10240]; ! 156: ssize_t rv; ! 157: ! 158: rv = recv(fd, buf, sizeof(buf), 0); ! 159: if (rv > 0) { ! 160: RecvEnqueue(buf, rv); ! 161: } ! 162: return rv; ! 163: } ! 164: ! 165: // インタフェース番号を返す。 ! 166: // auto のときは選択したインタフェース名を ifname にセットする。 ! 167: // インタフェースが決定できないときは errmsg をセットして 0 を返す。 ! 168: int ! 169: NetDriverAFPacket::SelectInterface() ! 170: { ! 171: int ifindex = 0; ! 172: struct ifaddrs *ifa_list, *ifa; ! 173: ! 174: if (ifname == "auto") { ! 175: // インタフェースを探す ! 176: int level = 1; ! 177: ! 178: if (getifaddrs(&ifa_list) == -1) { ! 179: errmsg = "getifaddrs"; ! 180: return 0; ! 181: } ! 182: ! 183: for (ifa = ifa_list; ifa; ifa = ifa->ifa_next) { ! 184: if ((ifa->ifa_flags & IFF_UP) == 0) { ! 185: continue; ! 186: } ! 187: if (ifa->ifa_addr == NULL) { ! 188: continue; ! 189: } ! 190: // AF_PACKET をサポートするインタフェースを探す ! 191: if (ifa->ifa_addr->sa_family != AF_PACKET) { ! 192: continue; ! 193: } ! 194: ! 195: // ETHERNET を探す ! 196: sockaddr_ll *sa = (sockaddr_ll *)ifa->ifa_addr; ! 197: if (sa->sll_hatype != ARPHRD_ETHER) { ! 198: continue; ! 199: } ! 200: ! 201: if (ifindex == 0) { ! 202: // 最初に見つかったものを採用 ! 203: ifname = ifa->ifa_name; ! 204: ifindex = sa->sll_ifindex; ! 205: } else { ! 206: // インタフェース候補が 2個以上ある場合はログレベル 0 にしたい ! 207: level = 0; ! 208: break; ! 209: } ! 210: } ! 211: freeifaddrs(ifa_list); ! 212: ! 213: if (ifindex == 0) { ! 214: errmsg = "auto could not find a suitable interface"; ! 215: return ifindex; ! 216: } ! 217: ! 218: putmsg(level, "auto-selected ifname \"%s\"", ifname.c_str()); ! 219: ! 220: } else { ! 221: ifindex = if_nametoindex(ifname.c_str()); ! 222: if (ifindex == 0) { ! 223: errmsg = string_format("interface %s not found", ifname.c_str()); ! 224: } ! 225: } ! 226: return ifindex; ! 227: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.