ruby-netmon-qt 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (304) hide show
  1. checksums.yaml +7 -0
  2. data/.rubocop.yml +10 -0
  3. data/.ruby-version +1 -0
  4. data/LICENSE +674 -0
  5. data/README.md +30 -0
  6. data/Rakefile +12 -0
  7. data/exe/netmon-qt +6 -0
  8. data/lib/netmon-qt/app/assets/README.md +6 -0
  9. data/lib/netmon-qt/app/assets/app.svg +1 -0
  10. data/lib/netmon-qt/app/assets/flags/ad.svg +148 -0
  11. data/lib/netmon-qt/app/assets/flags/ae.svg +6 -0
  12. data/lib/netmon-qt/app/assets/flags/af.svg +81 -0
  13. data/lib/netmon-qt/app/assets/flags/ag.svg +14 -0
  14. data/lib/netmon-qt/app/assets/flags/ai.svg +29 -0
  15. data/lib/netmon-qt/app/assets/flags/al.svg +5 -0
  16. data/lib/netmon-qt/app/assets/flags/am.svg +5 -0
  17. data/lib/netmon-qt/app/assets/flags/ao.svg +13 -0
  18. data/lib/netmon-qt/app/assets/flags/aq.svg +5 -0
  19. data/lib/netmon-qt/app/assets/flags/ar.svg +32 -0
  20. data/lib/netmon-qt/app/assets/flags/arab.svg +109 -0
  21. data/lib/netmon-qt/app/assets/flags/as.svg +73 -0
  22. data/lib/netmon-qt/app/assets/flags/asean.svg +13 -0
  23. data/lib/netmon-qt/app/assets/flags/at.svg +4 -0
  24. data/lib/netmon-qt/app/assets/flags/au.svg +8 -0
  25. data/lib/netmon-qt/app/assets/flags/aw.svg +186 -0
  26. data/lib/netmon-qt/app/assets/flags/ax.svg +18 -0
  27. data/lib/netmon-qt/app/assets/flags/az.svg +8 -0
  28. data/lib/netmon-qt/app/assets/flags/ba.svg +12 -0
  29. data/lib/netmon-qt/app/assets/flags/bb.svg +6 -0
  30. data/lib/netmon-qt/app/assets/flags/bd.svg +4 -0
  31. data/lib/netmon-qt/app/assets/flags/be.svg +7 -0
  32. data/lib/netmon-qt/app/assets/flags/bf.svg +7 -0
  33. data/lib/netmon-qt/app/assets/flags/bg.svg +5 -0
  34. data/lib/netmon-qt/app/assets/flags/bh.svg +4 -0
  35. data/lib/netmon-qt/app/assets/flags/bi.svg +15 -0
  36. data/lib/netmon-qt/app/assets/flags/bj.svg +14 -0
  37. data/lib/netmon-qt/app/assets/flags/bl.svg +7 -0
  38. data/lib/netmon-qt/app/assets/flags/bm.svg +97 -0
  39. data/lib/netmon-qt/app/assets/flags/bn.svg +36 -0
  40. data/lib/netmon-qt/app/assets/flags/bo.svg +674 -0
  41. data/lib/netmon-qt/app/assets/flags/bq.svg +5 -0
  42. data/lib/netmon-qt/app/assets/flags/br.svg +45 -0
  43. data/lib/netmon-qt/app/assets/flags/bs.svg +13 -0
  44. data/lib/netmon-qt/app/assets/flags/bt.svg +89 -0
  45. data/lib/netmon-qt/app/assets/flags/bv.svg +13 -0
  46. data/lib/netmon-qt/app/assets/flags/bw.svg +7 -0
  47. data/lib/netmon-qt/app/assets/flags/by.svg +18 -0
  48. data/lib/netmon-qt/app/assets/flags/bz.svg +145 -0
  49. data/lib/netmon-qt/app/assets/flags/ca.svg +4 -0
  50. data/lib/netmon-qt/app/assets/flags/cc.svg +19 -0
  51. data/lib/netmon-qt/app/assets/flags/cd.svg +12 -0
  52. data/lib/netmon-qt/app/assets/flags/cefta.svg +13 -0
  53. data/lib/netmon-qt/app/assets/flags/cf.svg +15 -0
  54. data/lib/netmon-qt/app/assets/flags/cg.svg +12 -0
  55. data/lib/netmon-qt/app/assets/flags/ch.svg +9 -0
  56. data/lib/netmon-qt/app/assets/flags/ci.svg +7 -0
  57. data/lib/netmon-qt/app/assets/flags/ck.svg +9 -0
  58. data/lib/netmon-qt/app/assets/flags/cl.svg +13 -0
  59. data/lib/netmon-qt/app/assets/flags/cm.svg +15 -0
  60. data/lib/netmon-qt/app/assets/flags/cn.svg +11 -0
  61. data/lib/netmon-qt/app/assets/flags/co.svg +7 -0
  62. data/lib/netmon-qt/app/assets/flags/cp.svg +7 -0
  63. data/lib/netmon-qt/app/assets/flags/cr.svg +7 -0
  64. data/lib/netmon-qt/app/assets/flags/cu.svg +13 -0
  65. data/lib/netmon-qt/app/assets/flags/cv.svg +13 -0
  66. data/lib/netmon-qt/app/assets/flags/cw.svg +14 -0
  67. data/lib/netmon-qt/app/assets/flags/cx.svg +15 -0
  68. data/lib/netmon-qt/app/assets/flags/cy.svg +6 -0
  69. data/lib/netmon-qt/app/assets/flags/cz.svg +5 -0
  70. data/lib/netmon-qt/app/assets/flags/de.svg +5 -0
  71. data/lib/netmon-qt/app/assets/flags/dg.svg +130 -0
  72. data/lib/netmon-qt/app/assets/flags/dj.svg +13 -0
  73. data/lib/netmon-qt/app/assets/flags/dk.svg +5 -0
  74. data/lib/netmon-qt/app/assets/flags/dm.svg +152 -0
  75. data/lib/netmon-qt/app/assets/flags/do.svg +122 -0
  76. data/lib/netmon-qt/app/assets/flags/dz.svg +5 -0
  77. data/lib/netmon-qt/app/assets/flags/eac.svg +48 -0
  78. data/lib/netmon-qt/app/assets/flags/ec.svg +138 -0
  79. data/lib/netmon-qt/app/assets/flags/ee.svg +5 -0
  80. data/lib/netmon-qt/app/assets/flags/eg.svg +38 -0
  81. data/lib/netmon-qt/app/assets/flags/eh.svg +11 -0
  82. data/lib/netmon-qt/app/assets/flags/er.svg +13 -0
  83. data/lib/netmon-qt/app/assets/flags/es-ct.svg +4 -0
  84. data/lib/netmon-qt/app/assets/flags/es-ga.svg +187 -0
  85. data/lib/netmon-qt/app/assets/flags/es-pv.svg +5 -0
  86. data/lib/netmon-qt/app/assets/flags/es.svg +547 -0
  87. data/lib/netmon-qt/app/assets/flags/et.svg +14 -0
  88. data/lib/netmon-qt/app/assets/flags/eu.svg +28 -0
  89. data/lib/netmon-qt/app/assets/flags/fi.svg +5 -0
  90. data/lib/netmon-qt/app/assets/flags/fj.svg +123 -0
  91. data/lib/netmon-qt/app/assets/flags/fk.svg +89 -0
  92. data/lib/netmon-qt/app/assets/flags/fm.svg +11 -0
  93. data/lib/netmon-qt/app/assets/flags/fo.svg +12 -0
  94. data/lib/netmon-qt/app/assets/flags/fr.svg +5 -0
  95. data/lib/netmon-qt/app/assets/flags/ga.svg +7 -0
  96. data/lib/netmon-qt/app/assets/flags/gb-eng.svg +5 -0
  97. data/lib/netmon-qt/app/assets/flags/gb-nir.svg +131 -0
  98. data/lib/netmon-qt/app/assets/flags/gb-sct.svg +4 -0
  99. data/lib/netmon-qt/app/assets/flags/gb-wls.svg +9 -0
  100. data/lib/netmon-qt/app/assets/flags/gb.svg +7 -0
  101. data/lib/netmon-qt/app/assets/flags/gd.svg +27 -0
  102. data/lib/netmon-qt/app/assets/flags/ge.svg +6 -0
  103. data/lib/netmon-qt/app/assets/flags/gf.svg +5 -0
  104. data/lib/netmon-qt/app/assets/flags/gg.svg +9 -0
  105. data/lib/netmon-qt/app/assets/flags/gh.svg +6 -0
  106. data/lib/netmon-qt/app/assets/flags/gi.svg +32 -0
  107. data/lib/netmon-qt/app/assets/flags/gl.svg +4 -0
  108. data/lib/netmon-qt/app/assets/flags/gm.svg +9 -0
  109. data/lib/netmon-qt/app/assets/flags/gn.svg +7 -0
  110. data/lib/netmon-qt/app/assets/flags/gp.svg +5 -0
  111. data/lib/netmon-qt/app/assets/flags/gq.svg +23 -0
  112. data/lib/netmon-qt/app/assets/flags/gr.svg +16 -0
  113. data/lib/netmon-qt/app/assets/flags/gs.svg +132 -0
  114. data/lib/netmon-qt/app/assets/flags/gt.svg +204 -0
  115. data/lib/netmon-qt/app/assets/flags/gu.svg +19 -0
  116. data/lib/netmon-qt/app/assets/flags/gw.svg +15 -0
  117. data/lib/netmon-qt/app/assets/flags/gy.svg +9 -0
  118. data/lib/netmon-qt/app/assets/flags/hk.svg +8 -0
  119. data/lib/netmon-qt/app/assets/flags/hm.svg +8 -0
  120. data/lib/netmon-qt/app/assets/flags/hn.svg +18 -0
  121. data/lib/netmon-qt/app/assets/flags/hr.svg +56 -0
  122. data/lib/netmon-qt/app/assets/flags/ht.svg +116 -0
  123. data/lib/netmon-qt/app/assets/flags/hu.svg +7 -0
  124. data/lib/netmon-qt/app/assets/flags/ic.svg +7 -0
  125. data/lib/netmon-qt/app/assets/flags/id.svg +4 -0
  126. data/lib/netmon-qt/app/assets/flags/ie.svg +7 -0
  127. data/lib/netmon-qt/app/assets/flags/il.svg +14 -0
  128. data/lib/netmon-qt/app/assets/flags/im.svg +36 -0
  129. data/lib/netmon-qt/app/assets/flags/in.svg +25 -0
  130. data/lib/netmon-qt/app/assets/flags/io.svg +130 -0
  131. data/lib/netmon-qt/app/assets/flags/iq.svg +10 -0
  132. data/lib/netmon-qt/app/assets/flags/ir.svg +219 -0
  133. data/lib/netmon-qt/app/assets/flags/is.svg +12 -0
  134. data/lib/netmon-qt/app/assets/flags/it.svg +7 -0
  135. data/lib/netmon-qt/app/assets/flags/je.svg +62 -0
  136. data/lib/netmon-qt/app/assets/flags/jm.svg +8 -0
  137. data/lib/netmon-qt/app/assets/flags/jo.svg +16 -0
  138. data/lib/netmon-qt/app/assets/flags/jp.svg +11 -0
  139. data/lib/netmon-qt/app/assets/flags/ke.svg +23 -0
  140. data/lib/netmon-qt/app/assets/flags/kg.svg +4 -0
  141. data/lib/netmon-qt/app/assets/flags/kh.svg +61 -0
  142. data/lib/netmon-qt/app/assets/flags/ki.svg +36 -0
  143. data/lib/netmon-qt/app/assets/flags/km.svg +16 -0
  144. data/lib/netmon-qt/app/assets/flags/kn.svg +14 -0
  145. data/lib/netmon-qt/app/assets/flags/kp.svg +15 -0
  146. data/lib/netmon-qt/app/assets/flags/kr.svg +17 -0
  147. data/lib/netmon-qt/app/assets/flags/kw.svg +13 -0
  148. data/lib/netmon-qt/app/assets/flags/ky.svg +103 -0
  149. data/lib/netmon-qt/app/assets/flags/kz.svg +36 -0
  150. data/lib/netmon-qt/app/assets/flags/la.svg +12 -0
  151. data/lib/netmon-qt/app/assets/flags/lb.svg +15 -0
  152. data/lib/netmon-qt/app/assets/flags/lc.svg +8 -0
  153. data/lib/netmon-qt/app/assets/flags/li.svg +43 -0
  154. data/lib/netmon-qt/app/assets/flags/lk.svg +22 -0
  155. data/lib/netmon-qt/app/assets/flags/lr.svg +14 -0
  156. data/lib/netmon-qt/app/assets/flags/ls.svg +8 -0
  157. data/lib/netmon-qt/app/assets/flags/lt.svg +7 -0
  158. data/lib/netmon-qt/app/assets/flags/lu.svg +5 -0
  159. data/lib/netmon-qt/app/assets/flags/lv.svg +6 -0
  160. data/lib/netmon-qt/app/assets/flags/ly.svg +13 -0
  161. data/lib/netmon-qt/app/assets/flags/ma.svg +4 -0
  162. data/lib/netmon-qt/app/assets/flags/mc.svg +6 -0
  163. data/lib/netmon-qt/app/assets/flags/md.svg +71 -0
  164. data/lib/netmon-qt/app/assets/flags/me.svg +118 -0
  165. data/lib/netmon-qt/app/assets/flags/mf.svg +5 -0
  166. data/lib/netmon-qt/app/assets/flags/mg.svg +7 -0
  167. data/lib/netmon-qt/app/assets/flags/mh.svg +8 -0
  168. data/lib/netmon-qt/app/assets/flags/mk.svg +5 -0
  169. data/lib/netmon-qt/app/assets/flags/ml.svg +7 -0
  170. data/lib/netmon-qt/app/assets/flags/mm.svg +10 -0
  171. data/lib/netmon-qt/app/assets/flags/mn.svg +14 -0
  172. data/lib/netmon-qt/app/assets/flags/mo.svg +9 -0
  173. data/lib/netmon-qt/app/assets/flags/mp.svg +86 -0
  174. data/lib/netmon-qt/app/assets/flags/mq.svg +5 -0
  175. data/lib/netmon-qt/app/assets/flags/mr.svg +6 -0
  176. data/lib/netmon-qt/app/assets/flags/ms.svg +25 -0
  177. data/lib/netmon-qt/app/assets/flags/mt.svg +56 -0
  178. data/lib/netmon-qt/app/assets/flags/mu.svg +8 -0
  179. data/lib/netmon-qt/app/assets/flags/mv.svg +6 -0
  180. data/lib/netmon-qt/app/assets/flags/mw.svg +15 -0
  181. data/lib/netmon-qt/app/assets/flags/mx.svg +377 -0
  182. data/lib/netmon-qt/app/assets/flags/my.svg +18 -0
  183. data/lib/netmon-qt/app/assets/flags/mz.svg +21 -0
  184. data/lib/netmon-qt/app/assets/flags/na.svg +16 -0
  185. data/lib/netmon-qt/app/assets/flags/nc.svg +12 -0
  186. data/lib/netmon-qt/app/assets/flags/ne.svg +6 -0
  187. data/lib/netmon-qt/app/assets/flags/nf.svg +11 -0
  188. data/lib/netmon-qt/app/assets/flags/ng.svg +6 -0
  189. data/lib/netmon-qt/app/assets/flags/ni.svg +129 -0
  190. data/lib/netmon-qt/app/assets/flags/nl.svg +5 -0
  191. data/lib/netmon-qt/app/assets/flags/no.svg +7 -0
  192. data/lib/netmon-qt/app/assets/flags/np.svg +18 -0
  193. data/lib/netmon-qt/app/assets/flags/nr.svg +12 -0
  194. data/lib/netmon-qt/app/assets/flags/nu.svg +10 -0
  195. data/lib/netmon-qt/app/assets/flags/nz.svg +36 -0
  196. data/lib/netmon-qt/app/assets/flags/om.svg +115 -0
  197. data/lib/netmon-qt/app/assets/flags/pa.svg +13 -0
  198. data/lib/netmon-qt/app/assets/flags/pc.svg +33 -0
  199. data/lib/netmon-qt/app/assets/flags/pe.svg +4 -0
  200. data/lib/netmon-qt/app/assets/flags/pf.svg +18 -0
  201. data/lib/netmon-qt/app/assets/flags/pg.svg +16 -0
  202. data/lib/netmon-qt/app/assets/flags/ph.svg +6 -0
  203. data/lib/netmon-qt/app/assets/flags/pk.svg +15 -0
  204. data/lib/netmon-qt/app/assets/flags/pl.svg +6 -0
  205. data/lib/netmon-qt/app/assets/flags/pm.svg +5 -0
  206. data/lib/netmon-qt/app/assets/flags/pn.svg +53 -0
  207. data/lib/netmon-qt/app/assets/flags/pr.svg +13 -0
  208. data/lib/netmon-qt/app/assets/flags/ps.svg +6 -0
  209. data/lib/netmon-qt/app/assets/flags/pt.svg +57 -0
  210. data/lib/netmon-qt/app/assets/flags/pw.svg +11 -0
  211. data/lib/netmon-qt/app/assets/flags/py.svg +156 -0
  212. data/lib/netmon-qt/app/assets/flags/qa.svg +4 -0
  213. data/lib/netmon-qt/app/assets/flags/re.svg +7 -0
  214. data/lib/netmon-qt/app/assets/flags/ro.svg +7 -0
  215. data/lib/netmon-qt/app/assets/flags/rs.svg +296 -0
  216. data/lib/netmon-qt/app/assets/flags/ru.svg +5 -0
  217. data/lib/netmon-qt/app/assets/flags/rw.svg +13 -0
  218. data/lib/netmon-qt/app/assets/flags/sa.svg +25 -0
  219. data/lib/netmon-qt/app/assets/flags/sb.svg +13 -0
  220. data/lib/netmon-qt/app/assets/flags/sc.svg +7 -0
  221. data/lib/netmon-qt/app/assets/flags/sd.svg +13 -0
  222. data/lib/netmon-qt/app/assets/flags/se.svg +4 -0
  223. data/lib/netmon-qt/app/assets/flags/sg.svg +13 -0
  224. data/lib/netmon-qt/app/assets/flags/sh-ac.svg +690 -0
  225. data/lib/netmon-qt/app/assets/flags/sh-hl.svg +164 -0
  226. data/lib/netmon-qt/app/assets/flags/sh-ta.svg +76 -0
  227. data/lib/netmon-qt/app/assets/flags/sh.svg +7 -0
  228. data/lib/netmon-qt/app/assets/flags/si.svg +18 -0
  229. data/lib/netmon-qt/app/assets/flags/sj.svg +7 -0
  230. data/lib/netmon-qt/app/assets/flags/sk.svg +9 -0
  231. data/lib/netmon-qt/app/assets/flags/sl.svg +12 -0
  232. data/lib/netmon-qt/app/assets/flags/sm.svg +73 -0
  233. data/lib/netmon-qt/app/assets/flags/sn.svg +8 -0
  234. data/lib/netmon-qt/app/assets/flags/so.svg +11 -0
  235. data/lib/netmon-qt/app/assets/flags/sr.svg +6 -0
  236. data/lib/netmon-qt/app/assets/flags/ss.svg +8 -0
  237. data/lib/netmon-qt/app/assets/flags/st.svg +16 -0
  238. data/lib/netmon-qt/app/assets/flags/sv.svg +593 -0
  239. data/lib/netmon-qt/app/assets/flags/sx.svg +56 -0
  240. data/lib/netmon-qt/app/assets/flags/sy.svg +6 -0
  241. data/lib/netmon-qt/app/assets/flags/sz.svg +34 -0
  242. data/lib/netmon-qt/app/assets/flags/tc.svg +50 -0
  243. data/lib/netmon-qt/app/assets/flags/td.svg +7 -0
  244. data/lib/netmon-qt/app/assets/flags/tf.svg +15 -0
  245. data/lib/netmon-qt/app/assets/flags/tg.svg +14 -0
  246. data/lib/netmon-qt/app/assets/flags/th.svg +7 -0
  247. data/lib/netmon-qt/app/assets/flags/tj.svg +26 -0
  248. data/lib/netmon-qt/app/assets/flags/tk.svg +5 -0
  249. data/lib/netmon-qt/app/assets/flags/tl.svg +13 -0
  250. data/lib/netmon-qt/app/assets/flags/tm.svg +205 -0
  251. data/lib/netmon-qt/app/assets/flags/tn.svg +4 -0
  252. data/lib/netmon-qt/app/assets/flags/to.svg +10 -0
  253. data/lib/netmon-qt/app/assets/flags/tr.svg +8 -0
  254. data/lib/netmon-qt/app/assets/flags/tt.svg +7 -0
  255. data/lib/netmon-qt/app/assets/flags/tv.svg +9 -0
  256. data/lib/netmon-qt/app/assets/flags/tw.svg +32 -0
  257. data/lib/netmon-qt/app/assets/flags/tz.svg +15 -0
  258. data/lib/netmon-qt/app/assets/flags/ua.svg +6 -0
  259. data/lib/netmon-qt/app/assets/flags/ug.svg +30 -0
  260. data/lib/netmon-qt/app/assets/flags/um.svg +9 -0
  261. data/lib/netmon-qt/app/assets/flags/un.svg +16 -0
  262. data/lib/netmon-qt/app/assets/flags/us.svg +9 -0
  263. data/lib/netmon-qt/app/assets/flags/uy.svg +28 -0
  264. data/lib/netmon-qt/app/assets/flags/uz.svg +30 -0
  265. data/lib/netmon-qt/app/assets/flags/va.svg +190 -0
  266. data/lib/netmon-qt/app/assets/flags/vc.svg +8 -0
  267. data/lib/netmon-qt/app/assets/flags/ve.svg +26 -0
  268. data/lib/netmon-qt/app/assets/flags/vg.svg +59 -0
  269. data/lib/netmon-qt/app/assets/flags/vi.svg +28 -0
  270. data/lib/netmon-qt/app/assets/flags/vn.svg +11 -0
  271. data/lib/netmon-qt/app/assets/flags/vu.svg +21 -0
  272. data/lib/netmon-qt/app/assets/flags/wf.svg +5 -0
  273. data/lib/netmon-qt/app/assets/flags/ws.svg +7 -0
  274. data/lib/netmon-qt/app/assets/flags/xk.svg +5 -0
  275. data/lib/netmon-qt/app/assets/flags/xx.svg +4 -0
  276. data/lib/netmon-qt/app/assets/flags/ye.svg +7 -0
  277. data/lib/netmon-qt/app/assets/flags/yt.svg +5 -0
  278. data/lib/netmon-qt/app/assets/flags/za.svg +17 -0
  279. data/lib/netmon-qt/app/assets/flags/zm.svg +27 -0
  280. data/lib/netmon-qt/app/assets/flags/zw.svg +21 -0
  281. data/lib/netmon-qt/app/components/connstableview/sortfilterproxymodel.rb +67 -0
  282. data/lib/netmon-qt/app/components/connstableview/statusbar.rb +73 -0
  283. data/lib/netmon-qt/app/components/connstableview/store.rb +236 -0
  284. data/lib/netmon-qt/app/components/connstableview.rb +239 -0
  285. data/lib/netmon-qt/app/components.rb +1 -0
  286. data/lib/netmon-qt/app/services/conns_lookup_service.rb +46 -0
  287. data/lib/netmon-qt/app/services.rb +1 -0
  288. data/lib/netmon-qt/app/views/mainwindow.rb +40 -0
  289. data/lib/netmon-qt/app/views.rb +1 -0
  290. data/lib/netmon-qt/app.rb +26 -0
  291. data/lib/netmon-qt/config/initializers/qt6.rb +8 -0
  292. data/lib/netmon-qt/config/settings.rb +33 -0
  293. data/lib/netmon-qt/config.rb +8 -0
  294. data/lib/netmon-qt/lib/contrib/sighandler.rb +24 -0
  295. data/lib/netmon-qt/lib/contrib.rb +1 -0
  296. data/lib/netmon-qt/lib/netmon/connection.rb +57 -0
  297. data/lib/netmon-qt/lib/netmon/localaddresscheck.rb +19 -0
  298. data/lib/netmon-qt/lib/netmon/procnet.rb +49 -0
  299. data/lib/netmon-qt/lib/netmon.rb +3 -0
  300. data/lib/netmon-qt/lib.rb +2 -0
  301. data/lib/netmon-qt/version.rb +3 -0
  302. data/lib/netmon-qt.rb +7 -0
  303. data/misc/screenshots/mainwindow.png +0 -0
  304. metadata +373 -0
@@ -0,0 +1,239 @@
1
+ require_relative "connstableview/sortfilterproxymodel"
2
+ require_relative "connstableview/statusbar"
3
+ require_relative "connstableview/store"
4
+
5
+ class ConnsTableView < RubyQt6::Bando::QWidget
6
+ QSS_BUTTON_AUTOREFRESH = "
7
+ QPushButton {
8
+ background: #EFF0F1;
9
+ color: #7F8C8D;
10
+ border: 1px solid #BCBEBF;
11
+ border-bottom: 3px solid #B0B0B0;
12
+ border-radius: 3px;
13
+ padding: 6px;
14
+ font-weight: bold;
15
+ }
16
+ QPushButton:checked {
17
+ background: #FFFFFF;
18
+ color: #31363B;
19
+ }
20
+ "
21
+
22
+ q_object do
23
+ slot "_on_filter_changed()"
24
+ slot "_on_autorefreshbtn_toggled(bool)"
25
+ slot "_on_autorefresh_timer_timeout()"
26
+ slot "_on_tableview_custom_context_menu_requested(QPoint)"
27
+ slot "_on_endprocess_action_triggered()"
28
+ slot "_on_whois_action_triggered()"
29
+ slot "_on_copy_action_triggered()"
30
+ end
31
+
32
+ attr_reader :processfilter, :protocolfilter, :statefilter, :userfilter
33
+ attr_reader :statusbar
34
+
35
+ def initialize
36
+ super
37
+
38
+ @lastindex = nil
39
+
40
+ initialize_store
41
+ initialize_actions
42
+ initialize_toolbar
43
+ initialize_tableview
44
+ initialize_statusbar
45
+ initialize_timer_autorefresh
46
+
47
+ mainlayout = QVBoxLayout.new(self)
48
+ mainlayout.add_widget(@toolbar)
49
+ mainlayout.add_widget(@tableview)
50
+
51
+ @userfilter.set_current_text(Etc.getpwuid.name)
52
+ @autorefreshbtn.set_checked(true)
53
+ end
54
+
55
+ private
56
+
57
+ def initialize_store
58
+ @store = Store.new(self)
59
+ end
60
+
61
+ def initialize_actions
62
+ @endprocess_action = initialize_actions_act(QIcon::ThemeIcon::ApplicationExit, "End Process", :_on_endprocess_action_triggered)
63
+ @whois_action = initialize_actions_act(QIcon::ThemeIcon::EditFind, "", :_on_whois_action_triggered)
64
+ @copy_action = initialize_actions_act(QIcon::ThemeIcon::EditCopy, "", :_on_copy_action_triggered)
65
+ end
66
+
67
+ def initialize_actions_act(icon, text, slot)
68
+ action = QAction.new(QIcon.from_theme(icon), text, self)
69
+ action.triggered.connect(self, slot)
70
+ action
71
+ end
72
+
73
+ def initialize_toolbar
74
+ @processfilter = QComboBox.new
75
+ @processfilter.set_fixed_width(128)
76
+ @processfilter.add_item("*")
77
+ @store.active_processes.each { |process| @processfilter.add_item(process) }
78
+ @processfilter.current_text_changed.connect(self, :_on_filter_changed)
79
+
80
+ @protocolfilter = QComboBox.new
81
+ @protocolfilter.add_item("*")
82
+ @store.active_protocols.each { |protocol| @protocolfilter.add_item(protocol) }
83
+ @protocolfilter.set_fixed_width(128)
84
+ @protocolfilter.current_text_changed.connect(self, :_on_filter_changed)
85
+
86
+ @statefilter = QComboBox.new
87
+ @statefilter.add_item("*")
88
+ @store.active_states.each { |state| @statefilter.add_item(state) }
89
+ @statefilter.set_fixed_width(128)
90
+ @statefilter.current_text_changed.connect(self, :_on_filter_changed)
91
+
92
+ @userfilter = QComboBox.new
93
+ @userfilter.set_fixed_width(128)
94
+ @userfilter.add_item("*")
95
+ @store.active_users.each { |user| @userfilter.add_item(user) }
96
+ @userfilter.current_text_changed.connect(self, :_on_filter_changed)
97
+
98
+ @autorefreshbtn = QPushButton.new("")
99
+ @autorefreshbtn.set_fixed_width(192)
100
+ @autorefreshbtn.set_style_sheet(QSS_BUTTON_AUTOREFRESH)
101
+ @autorefreshbtn.set_checkable(true)
102
+ @autorefreshbtn.toggled.connect(self, :_on_autorefreshbtn_toggled)
103
+
104
+ @toolbar = QWidget.new
105
+ @toolbarlayout = QHBoxLayout.new(@toolbar)
106
+ @toolbarlayout.add_widget(initialize_toolbar_label("Process:"))
107
+ @toolbarlayout.add_widget(@processfilter)
108
+ @toolbarlayout.add_spacing(8)
109
+ @toolbarlayout.add_widget(initialize_toolbar_label("Protocol:"))
110
+ @toolbarlayout.add_widget(@protocolfilter)
111
+ @toolbarlayout.add_spacing(8)
112
+ @toolbarlayout.add_widget(initialize_toolbar_label("State:"))
113
+ @toolbarlayout.add_widget(@statefilter)
114
+ @toolbarlayout.add_spacing(8)
115
+ @toolbarlayout.add_widget(initialize_toolbar_label("User:"))
116
+ @toolbarlayout.add_widget(@userfilter)
117
+ @toolbarlayout.add_stretch
118
+ @toolbarlayout.add_widget(@autorefreshbtn)
119
+ end
120
+
121
+ def initialize_toolbar_label(text)
122
+ label = QLabel.new(text)
123
+ label.set_fixed_width(64)
124
+ label
125
+ end
126
+
127
+ def initialize_tableview
128
+ @tableview = QTableView.new
129
+ @tableview.set_selection_behavior(QAbstractItemView::SelectRows)
130
+ @tableview.set_selection_mode(QAbstractItemView::SingleSelection)
131
+ @tableview.set_context_menu_policy(Qt::ContextMenuPolicy::CustomContextMenu)
132
+ @tableview.custom_context_menu_requested.connect(self, :_on_tableview_custom_context_menu_requested)
133
+
134
+ @storeproxymodel = SortFilterProxyModel.new(self)
135
+ @storeproxymodel.set_source_model(@store.itemmodel)
136
+ @tableview.set_model(@storeproxymodel)
137
+
138
+ @tableview.horizontal_header.hide_section(0)
139
+ @tableview.vertical_header.set_visible(false)
140
+ @tableview.set_column_width(COLUMN_PROCESS_NAME, 128)
141
+ @tableview.set_column_width(COLUMN_LOCAL_ADDRESS, 192)
142
+ @tableview.set_column_width(COLUMN_REMOTE_ADDRESS, 192)
143
+
144
+ @tableview.sort_by_column(COLUMN_PROCESS_NAME, Qt::AscendingOrder)
145
+ @tableview.set_sorting_enabled(true)
146
+ end
147
+
148
+ def initialize_statusbar
149
+ @statusbar = StatusBar.new(@storeproxymodel)
150
+ end
151
+
152
+ def initialize_timer_autorefresh
153
+ @timer = QTimer.new(self)
154
+ @timer.set_interval(NetmonQt.settings.GET_connections_check_interval)
155
+ @timer.timeout.connect(self, :_on_autorefresh_timer_timeout)
156
+ end
157
+
158
+ def update_filter_additem(filter, items)
159
+ index = filter.count - 1
160
+ items.reverse_each do |item|
161
+ loop do
162
+ case filter.item_text(index) <=> item
163
+ when +0 then break
164
+ when +1 then (index -= 1) || next
165
+ when -1 then filter.insert_item(index + 1, item) || break
166
+ end
167
+ end
168
+ end
169
+ end
170
+
171
+ def _on_filter_changed
172
+ @storeproxymodel.invalidate
173
+ @statusbar.refresh
174
+ end
175
+
176
+ def _on_autorefreshbtn_toggled(checked)
177
+ if checked
178
+ @autorefreshbtn.set_text("Auto Refresh: ON")
179
+ @timer.start
180
+ _on_autorefresh_timer_timeout
181
+ else
182
+ @autorefreshbtn.set_text("Auto Refresh: OFF")
183
+ @timer.stop
184
+ end
185
+ end
186
+
187
+ def _on_autorefresh_timer_timeout
188
+ @store.refresh
189
+
190
+ update_filter_additem(@processfilter, @store.active_processes)
191
+ update_filter_additem(@userfilter, @store.active_users)
192
+ _on_filter_changed
193
+ end
194
+
195
+ def _on_tableview_custom_context_menu_requested(position)
196
+ @lastindex = @tableview.index_at(position)
197
+ return unless @lastindex.valid?
198
+
199
+ menu = QMenu.new("", self)
200
+ menu.set_attribute(Qt::WA_DeleteOnClose)
201
+
202
+ pid = @lastindex.sibling_at_column(COLUMN_PROCESS_ID).data.value.to_s
203
+ remote_address = @lastindex.sibling_at_column(COLUMN_REMOTE_ADDRESS).data.value
204
+ remote_address = remote_address.contains(".") ? remote_address : "#{remote_address[0, 12]}..."
205
+
206
+ @endprocess_action.set_enabled(pid.to_i.nonzero?)
207
+ @whois_action.set_text("Whois #{remote_address} - via IPinfo")
208
+ @copy_action.set_text("Copy \"#{@lastindex.data.value}\"")
209
+
210
+ menu.add_action(@endprocess_action)
211
+ menu.add_separator
212
+ menu.add_action(@whois_action)
213
+ menu.add_action(@copy_action)
214
+
215
+ menu.exec(@tableview.viewport.map_to_global(position))
216
+ end
217
+
218
+ def _on_endprocess_action_triggered
219
+ return unless @lastindex.valid?
220
+
221
+ pid = @lastindex.sibling_at_column(COLUMN_PROCESS_ID).data.value
222
+ QProcess.execute("kill", QStringList.new << "-9" << pid)
223
+ end
224
+
225
+ def _on_whois_action_triggered
226
+ return unless @lastindex.valid?
227
+
228
+ remote_address = @lastindex.sibling_at_column(COLUMN_REMOTE_ADDRESS).data.value
229
+ url = QUrl.new("https://ipinfo.io/#{remote_address}")
230
+ QDesktopServices.open_url(url)
231
+ end
232
+
233
+ def _on_copy_action_triggered
234
+ return unless @lastindex.valid?
235
+
236
+ text = @lastindex.data.value
237
+ QApplication.clipboard.set_text(text)
238
+ end
239
+ end
@@ -0,0 +1 @@
1
+ require_relative "components/connstableview"
@@ -0,0 +1,46 @@
1
+ class ConnsLookupService
2
+ def perform
3
+ conns = {}
4
+ ino2conn = {}
5
+
6
+ %w[tcp tcp6 udp udp6].each do |filename|
7
+ str = File.read("/proc/net/#{filename}")
8
+ sockets = Netmon::ProcNet.sockets_form_str(str)
9
+ sockets.each do |socket|
10
+ conn = Netmon::Connection.new(socket)
11
+ conn.protocol = conn_protocol(filename)
12
+ conns[conn.key] = conn
13
+ ino2conn[conn.inode] = conn
14
+ end
15
+ end
16
+
17
+ Dir.glob("/proc/[1-9]*/fd/[1-9]*") do |dir|
18
+ ino = File.stat(dir).ino
19
+ conn = ino2conn[ino]
20
+ next if conn.nil?
21
+
22
+ conn.pid = dir.split("/")[2].to_i
23
+ conn.comm = File.read("/proc/#{conn.pid}/comm").strip
24
+ rescue Errno::EACCES, Errno::ENOENT
25
+ end
26
+
27
+ conns
28
+ end
29
+
30
+ private
31
+
32
+ def conn_protocol(str)
33
+ case str
34
+ when "tcp"
35
+ Netmon::Connection::PROTOCOL_TCP4
36
+ when "tcp6"
37
+ Netmon::Connection::PROTOCOL_TCP6
38
+ when "udp"
39
+ Netmon::Connection::PROTOCOL_UDP4
40
+ when "udp6"
41
+ Netmon::Connection::PROTOCOL_UDP6
42
+ else
43
+ ""
44
+ end
45
+ end
46
+ end
@@ -0,0 +1 @@
1
+ require_relative "services/conns_lookup_service"
@@ -0,0 +1,40 @@
1
+ class MainWindow < RubyQt6::Bando::QMainWindow
2
+ q_object do
3
+ end
4
+
5
+ def initialize
6
+ super
7
+
8
+ initialize_central_widget
9
+ initialize_statusbar
10
+
11
+ set_context_menu_policy(Qt::NoContextMenu)
12
+ NetmonQt.settings.GET_mainwindow_geometry_and_restore_to(self)
13
+ end
14
+
15
+ def close_event(evt)
16
+ NetmonQt.settings.PUT_mainwindow_geometry(self)
17
+
18
+ _close_event(evt)
19
+ end
20
+
21
+ private
22
+
23
+ def initialize_central_widget
24
+ @connstableview = ConnsTableView.new
25
+
26
+ centralwidget = QWidget.new
27
+ mainlayout = QHBoxLayout.new(centralwidget)
28
+ mainlayout.add_widget(@connstableview)
29
+
30
+ set_central_widget(centralwidget)
31
+ end
32
+
33
+ def initialize_statusbar
34
+ statusbar = QStatusBar.new
35
+ statusbar.set_contents_margins(12, 0, 12, 0)
36
+ statusbar.add_permanent_widget(@connstableview.statusbar, 1)
37
+
38
+ set_status_bar(statusbar)
39
+ end
40
+ end
@@ -0,0 +1 @@
1
+ require_relative "views/mainwindow"
@@ -0,0 +1,26 @@
1
+ require_relative "config"
2
+ require_relative "lib"
3
+
4
+ require_relative "app/components"
5
+ require_relative "app/services"
6
+ require_relative "app/views"
7
+
8
+ module NetmonQt
9
+ class Application
10
+ def self.run
11
+ new.exec
12
+ end
13
+
14
+ def initialize
15
+ @app = QApplication.new
16
+ @mainwindow = MainWindow.new
17
+ end
18
+
19
+ def exec
20
+ Contrib::SigHandler.new(@app)
21
+
22
+ @mainwindow.show
23
+ @app.exec
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,8 @@
1
+ QApplication.set_organization_name("souk4711")
2
+ QApplication.set_application_name("NetmonQt")
3
+
4
+ root_path = File.expand_path("../..", __dir__)
5
+ QDir.add_search_path("assets", File.join(root_path, "app/assets"))
6
+
7
+ icon = QIcon.new("assets:/app.svg")
8
+ QApplication.set_window_icon(icon)
@@ -0,0 +1,33 @@
1
+ module NetmonQt
2
+ class Settings
3
+ def GET_mainwindow_geometry_and_restore_to(mainwindow)
4
+ settings = QSettings.new
5
+ mainwindow.restore_geometry(settings.value("MainWindow/geometry", QByteArray.new("")))
6
+ mainwindow.restore_state(settings.value("MainWindow/windowState", QByteArray.new("")))
7
+ end
8
+
9
+ def PUT_mainwindow_geometry(mainwindow)
10
+ settings = QSettings.new
11
+ settings.set_value("MainWindow/geometry", mainwindow.save_geometry)
12
+ settings.set_value("MainWindow/windowState", mainwindow.save_state)
13
+ end
14
+
15
+ def GET_connections_check_interval
16
+ default_connections_check_interval
17
+ end
18
+
19
+ def GET_geolite2_mmdb
20
+ default_geolite2_mmdb
21
+ end
22
+
23
+ private
24
+
25
+ def default_connections_check_interval
26
+ 4_000
27
+ end
28
+
29
+ def default_geolite2_mmdb
30
+ "/usr/share/GeoIP/GeoLite2-Country.mmdb"
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,8 @@
1
+ require_relative "config/initializers/qt6"
2
+ require_relative "config/settings"
3
+
4
+ module NetmonQt
5
+ def self.settings
6
+ @settings ||= Settings.new
7
+ end
8
+ end
@@ -0,0 +1,24 @@
1
+ module Contrib
2
+ class SigHandler < RubyQt6::Bando::QObject
3
+ q_object do
4
+ slot "_noop()"
5
+ end
6
+
7
+ def initialize(parent)
8
+ super
9
+
10
+ ["INT", "TERM"].each do |sig|
11
+ Signal.trap(sig) { |_| QApplication.quit }
12
+ end
13
+
14
+ timer = QTimer.new(self)
15
+ timer.timeout.connect(self, :_noop)
16
+ timer.start(1_000)
17
+ end
18
+
19
+ private
20
+
21
+ def _noop
22
+ end
23
+ end
24
+ end
@@ -0,0 +1 @@
1
+ require_relative "contrib/sighandler"
@@ -0,0 +1,57 @@
1
+ module Netmon
2
+ class Connection
3
+ # rubocop:disable Layout
4
+ PROTOCOL_TCP = "TCP"
5
+ PROTOCOL_UDP = "UDP"
6
+ PROTOCOL_TCP4 = "TCP v4"
7
+ PROTOCOL_TCP6 = "TCP v6"
8
+ PROTOCOL_UDP4 = "UDP v4"
9
+ PROTOCOL_UDP6 = "UDP v6"
10
+
11
+ STATE_ESTABLISHED = "ESTABLISHED"
12
+ STATE_LISTEN = "LISTEN"
13
+ STATE_SYN_SENT = "SYN_SENT"
14
+ STATE_SYN_RECV = "SYN_RECV"
15
+ STATE_FIN_WAIT1 = "FIN_WAIT1"
16
+ STATE_FIN_WAIT2 = "FIN_WAIT2"
17
+ STATE_CLOSING = "CLOSING"
18
+ STATE_CLOSE_WAIT = "CLOSE_WAIT"
19
+ STATE_LAST_ACK = "LAST_ACK"
20
+ STATE_TIME_WAIT = "TIME_WAIT"
21
+ STATE_CLOSE = "CLOSE"
22
+
23
+ COMM_DEFUNCT = "<defunct>"
24
+ COMM_UNKNOWN = "<unknown>"
25
+ # rubocop:enable Layout
26
+
27
+ attr_accessor :protocol
28
+ attr_accessor :local_address, :local_port
29
+ attr_accessor :remote_address, :remote_port
30
+ attr_accessor :state, :uid, :inode
31
+ attr_accessor :pid, :comm
32
+
33
+ def initialize(attrs)
34
+ attrs.each do |attr, value|
35
+ public_send("#{attr}=", value)
36
+ end
37
+ end
38
+
39
+ def key
40
+ "#{protocol}: #{local_address}:#{local_port} <=> #{remote_address}:#{remote_port}"
41
+ end
42
+
43
+ def uname
44
+ Etc.getpwuid(uid).name
45
+ end
46
+
47
+ def pid_text
48
+ return pid.to_s if pid
49
+ inode.zero? ? COMM_DEFUNCT : COMM_UNKNOWN
50
+ end
51
+
52
+ def comm_text
53
+ return comm if comm
54
+ inode.zero? ? COMM_DEFUNCT : COMM_UNKNOWN
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,19 @@
1
+ require "ipaddr"
2
+
3
+ module Netmon
4
+ CIDR_LIST = [
5
+ IPAddr.new("224.0.0.0/24"), # Local Multicast - IPv4
6
+ IPAddr.new("ff02::/16"), # Local Multicast - IPv6
7
+ IPAddr.new("0.0.0.0"), # Unspecified - IPv4
8
+ IPAddr.new("::") # Unspecified - IPv6
9
+ ].freeze
10
+
11
+ def self.local_address?(address)
12
+ ip = IPAddr.new(address)
13
+ return true if ip.link_local?
14
+ return true if ip.loopback?
15
+ return true if ip.private?
16
+ return true if CIDR_LIST.any? { |cidr| cidr.include?(address) }
17
+ false
18
+ end
19
+ end
@@ -0,0 +1,49 @@
1
+ module Netmon
2
+ module ProcNet
3
+ TCP_STATE = {
4
+ "01" => Connection::STATE_ESTABLISHED,
5
+ "02" => Connection::STATE_SYN_SENT,
6
+ "03" => Connection::STATE_SYN_RECV,
7
+ "04" => Connection::STATE_FIN_WAIT1,
8
+ "05" => Connection::STATE_FIN_WAIT2,
9
+ "06" => Connection::STATE_TIME_WAIT,
10
+ "07" => Connection::STATE_CLOSE,
11
+ "08" => Connection::STATE_CLOSE_WAIT,
12
+ "09" => Connection::STATE_LAST_ACK,
13
+ "0A" => Connection::STATE_LISTEN,
14
+ "0B" => Connection::STATE_CLOSING
15
+ }.freeze
16
+
17
+ def self.sockets_form_str(str)
18
+ str.lines[1..].map do |line|
19
+ linesplit = line.split
20
+ local_address, local_port = linesplit[1].split(":")
21
+ remote_address, remote_port = linesplit[2].split(":")
22
+
23
+ {
24
+ local_address: format_address(local_address),
25
+ local_port: format_port(local_port),
26
+ remote_address: format_address(remote_address),
27
+ remote_port: format_port(remote_port),
28
+ state: TCP_STATE[linesplit[3]],
29
+ uid: linesplit[7].to_i,
30
+ inode: linesplit[9].to_i
31
+ }
32
+ end
33
+ end
34
+
35
+ def self.format_address(str)
36
+ case str.size
37
+ when 8 then str.scan(/.{2}/).reverse.map { |s| s.to_i(16) }.join(".")
38
+ when 32 then str.scan(/.{8}/).map { |s| s.scan(/.{2}/).reverse }.join.scan(/.{4}/).join(":")
39
+ else raise "Invalid address str: #{str}"
40
+ end
41
+ end
42
+ private_class_method :format_address
43
+
44
+ def self.format_port(str)
45
+ str.to_i(16)
46
+ end
47
+ private_class_method :format_port
48
+ end
49
+ end
@@ -0,0 +1,3 @@
1
+ require_relative "netmon/connection"
2
+ require_relative "netmon/localaddresscheck"
3
+ require_relative "netmon/procnet"
@@ -0,0 +1,2 @@
1
+ require_relative "lib/contrib"
2
+ require_relative "lib/netmon"
@@ -0,0 +1,3 @@
1
+ module NetmonQt
2
+ VERSION = "1.0.0"
3
+ end
data/lib/netmon-qt.rb ADDED
@@ -0,0 +1,7 @@
1
+ require "etc"
2
+
3
+ require "maxmind/db"
4
+ require "qt6/qtwidgets"
5
+
6
+ require_relative "netmon-qt/app"
7
+ require_relative "netmon-qt/version"
Binary file