]> git.stg.codes - stg.git/blob - projects/stargazer/plugins/capture/ether_linux/ether_cap.cpp
More subscriptions, less notifiers.
[stg.git] / projects / stargazer / plugins / capture / ether_linux / ether_cap.cpp
1 /*
2  *    This program is free software; you can redistribute it and/or modify
3  *    it under the terms of the GNU General Public License as published by
4  *    the Free Software Foundation; either version 2 of the License, or
5  *    (at your option) any later version.
6  *
7  *    This program is distributed in the hope that it will be useful,
8  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
9  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  *    GNU General Public License for more details.
11  *
12  *    You should have received a copy of the GNU General Public License
13  *    along with this program; if not, write to the Free Software
14  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
15  */
16
17 /*
18 Date: 18.09.2002
19 */
20
21 /*
22 * Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
23 */
24
25 /*
26 $Revision: 1.23 $
27 $Date: 2009/12/13 13:45:13 $
28 */
29
30 #include "ether_cap.h"
31
32 #include "stg/common.h"
33 #include "stg/raw_ip_packet.h"
34 #include "stg/traffcounter.h"
35
36 #include <cstdio>
37 #include <cstdlib>
38 #include <cstring>
39 #include <cerrno>
40 #include <csignal>
41
42 #include <sys/socket.h>
43 #include <arpa/inet.h>
44 #include <netinet/in.h>
45 #include <sys/types.h>
46 #include <unistd.h>
47 #include <linux/if_ether.h>
48 #include <linux/if_packet.h>
49 #include <sys/ioctl.h>
50 #include <net/if.h>
51
52 //#define CAP_DEBUG 1
53
54 extern "C" STG::Plugin* GetPlugin()
55 {
56     static ETHER_CAP plugin;
57     return &plugin;
58 }
59 //-----------------------------------------------------------------------------
60 //-----------------------------------------------------------------------------
61 //-----------------------------------------------------------------------------
62 std::string ETHER_CAP::GetVersion() const
63 {
64 return "cap_ether v.1.2";
65 }
66 //-----------------------------------------------------------------------------
67 ETHER_CAP::ETHER_CAP()
68     : isRunning(false),
69       capSock(-1),
70       traffCnt(NULL),
71       logger(STG::PluginLogger::get("cap_ether"))
72 {
73 }
74 //-----------------------------------------------------------------------------
75 int ETHER_CAP::Start()
76 {
77 if (isRunning)
78     return 0;
79
80 if (EthCapOpen() < 0)
81     {
82     errorStr = "Cannot open socket!";
83     printfd(__FILE__, "Cannot open socket\n");
84     return -1;
85     }
86
87 m_thread = std::jthread([this](auto token){ Run(std::move(token)); });
88
89 return 0;
90 }
91 //-----------------------------------------------------------------------------
92 int ETHER_CAP::Stop()
93 {
94 if (!isRunning)
95     return 0;
96
97 m_thread.request_stop();
98
99 //5 seconds to thread stops itself
100 for (int i = 0; i < 25 && isRunning; i++)
101     {
102     struct timespec ts = {0, 200000000};
103     nanosleep(&ts, NULL);
104     }
105 //after 5 seconds waiting thread still running. now killing it
106 if (isRunning)
107     m_thread.detach();
108 else
109     m_thread.join();
110
111 EthCapClose();
112 return 0;
113 }
114 //-----------------------------------------------------------------------------
115 void ETHER_CAP::Run(std::stop_token token)
116 {
117 sigset_t signalSet;
118 sigfillset(&signalSet);
119 pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
120
121 isRunning = true;
122
123 struct ETH_IP
124 {
125 uint16_t    ethHdr[8];
126 STG::RawPacket  rp;
127 char        padding[4];
128 char        padding1[8];
129 };
130
131 char ethip[sizeof(ETH_IP)];
132
133 memset(&ethip, 0, sizeof(ETH_IP));
134
135 ETH_IP * ethIP = static_cast<ETH_IP *>(static_cast<void *>(&ethip));
136 ethIP->rp.dataLen = -1;
137
138 char * iface = NULL;
139
140 while (!token.stop_requested())
141     {
142     if (EthCapRead(&ethip, 68 + 14, &iface))
143         {
144         continue;
145         }
146
147     if (ethIP->ethHdr[7] != 0x8)
148         continue;
149
150     traffCnt->process(ethIP->rp);
151     }
152
153 isRunning = false;
154 }
155 //-----------------------------------------------------------------------------
156 int ETHER_CAP::EthCapOpen()
157 {
158 capSock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
159 if (capSock < 0)
160     logger("Cannot create socket: %s", strerror(errno));
161 return capSock;
162 }
163 //-----------------------------------------------------------------------------
164 int ETHER_CAP::EthCapClose()
165 {
166 close(capSock);
167 return 0;
168 }
169 //-----------------------------------------------------------------------------
170 int ETHER_CAP::EthCapRead(void * buffer, int blen, char **)
171 {
172 struct sockaddr_ll  addr;
173 socklen_t addrLen;
174
175 if (!WaitPackets(capSock))
176     {
177     return ENODATA;
178     }
179
180 addrLen = sizeof(addr);
181
182 if (recvfrom(capSock, static_cast<char*>(buffer) + 2, blen, 0, reinterpret_cast<sockaddr *>(&addr), &addrLen) < 0)
183     {
184     logger("recvfrom error: %s", strerror(errno));
185     return ENODATA;
186     }
187
188 return 0;
189 }