minancy commited on
Commit
1a52323
·
1 Parent(s): 95917b6

new version analyze

Browse files
Files changed (1) hide show
  1. sections/analyze.py +137 -8
sections/analyze.py CHANGED
@@ -1,5 +1,8 @@
1
  import polars as pl
2
  import streamlit as st
 
 
 
3
 
4
  if "parsed_df" not in st.session_state:
5
  st.session_state.parsed_df = None
@@ -14,6 +17,20 @@ if st.session_state.parsed_df is None:
14
 
15
  data = st.session_state.parsed_df
16
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  # Créer les onglets principaux
18
  tab1, tab2, tab3, tab4 = st.tabs(
19
  ["Dataviz", "Analysis", "Foreign IP addresses", "Sankey"]
@@ -172,17 +189,129 @@ with tab2:
172
  )
173
  st.dataframe(top_ips, use_container_width=True)
174
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
175
 
176
  # Onglet Foreign IP addresses
177
  with tab3:
178
- # Afficher ici la liste des accès hors plan d’adressage universitaire
179
- st.write("### 🚫 List of access outside the university network")
180
- external_access = data.filter(
181
- ~pl.col("ipdst").cast(pl.Utf8).str.contains(r"^192\.168\.")
182
- & ~pl.col("ipdst").cast(pl.Utf8).str.contains(r"^10\.79\.")
183
- & ~pl.col("ipdst").cast(pl.Utf8).str.contains(r"^159\.84\.")
184
- )
185
- st.dataframe(external_access, use_container_width=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
186
 
187
  # Onglet Sankey
188
  with tab4:
 
1
  import polars as pl
2
  import streamlit as st
3
+ import ipaddress
4
+ import plotly.express as px
5
+ import pandas as pd
6
 
7
  if "parsed_df" not in st.session_state:
8
  st.session_state.parsed_df = None
 
17
 
18
  data = st.session_state.parsed_df
19
 
20
+ university_subnets = [
21
+ ipaddress.ip_network("192.168.0.0/16"),
22
+ ipaddress.ip_network("10.79.0.0/16"),
23
+ ipaddress.ip_network("159.84.0.0/16"),
24
+ ]
25
+
26
+ # Fonction pour vérifier si une IP appartient aux sous-réseaux universitaires
27
+ def is_university_ip(ip):
28
+ try:
29
+ ip_obj = ipaddress.ip_address(ip)
30
+ return any(ip_obj in subnet for subnet in university_subnets)
31
+ except ValueError:
32
+ return False
33
+
34
  # Créer les onglets principaux
35
  tab1, tab2, tab3, tab4 = st.tabs(
36
  ["Dataviz", "Analysis", "Foreign IP addresses", "Sankey"]
 
189
  )
190
  st.dataframe(top_ips, use_container_width=True)
191
 
192
+ # Graphique
193
+
194
+ st.write("### 🔴 Analysis of Blocked Attempts")
195
+
196
+ if "ipsrc" in data.columns and "action" in data.columns:
197
+ # Filtrer uniquement les tentatives bloquées
198
+ blocked_attempts = data.filter(pl.col("action") == "DENY")
199
+
200
+ # Compter les occurrences des IP sources bloquées
201
+ blocked_ips = (
202
+ blocked_attempts
203
+ .group_by("ipsrc")
204
+ .agg(pl.count("ipsrc").alias("count"))
205
+ .sort("count", descending=True)
206
+ )
207
+
208
+
209
+ top_n = st.slider(" ", 5, 20, 10, key="top_n_slider")
210
+
211
+ # Sélectionner le Top N des IP bloquées
212
+ top_blocked_ips = blocked_ips.head(top_n)
213
+
214
+
215
+ # ---- GRAPHIQUE AVEC PLOTLY ----
216
+ color_palette = px.colors.sequential.Blues
217
+ if not top_blocked_ips.is_empty():
218
+ fig = px.bar(
219
+ top_blocked_ips.to_pandas(), # Convertir en DataFrame Pandas pour Plotly
220
+ x="count",
221
+ y="ipsrc",
222
+ orientation="h",
223
+ text="count",
224
+ title=f"Top {top_n} Most Blocked IPs",
225
+ labels={"ipsrc": "IP Source", "count": "Number of Blocked Attempts"},
226
+ color_discrete_sequence=["#3d85c6"]
227
+ )
228
+
229
+ # Amélioration du layout
230
+ fig.update_traces(texttemplate='%{text}', textposition='inside')
231
+ fig.update_layout(yaxis=dict(categoryorder="total ascending"))
232
+
233
+ # Afficher le graphique interactif
234
+ st.plotly_chart(fig, use_container_width=True)
235
+ else:
236
+ st.info("No blocked attempts found.")
237
+ else:
238
+ st.warning("Columns 'ipsrc' or 'action' not found.")
239
+
240
+ # Graphique de série temporelle des connexions par heure
241
+ st.write("### 📊 Hourly Connection Activity")
242
+
243
+ if "timestamp" in data.columns:
244
+ # Extraire uniquement les connexions autorisées (PERMIT) et valider le format datetime
245
+ activity_data = (
246
+ data
247
+ .filter(pl.col("action") == "PERMIT") # Ne garder que les connexions autorisées
248
+ .with_columns(pl.col("timestamp").dt.strftime("%Y-%m-%d %H:00:00").alias("hour")) # Normaliser à l'heure
249
+ .group_by("hour")
250
+ .agg(pl.count("hour").alias("connection_count")) # Compter les connexions par heure
251
+ .sort("hour") # Trier chronologiquement
252
+ )
253
+
254
+ # Vérifier si on a des données après filtrage
255
+ if not activity_data.is_empty():
256
+ # Convertir en DataFrame Pandas pour Plotly
257
+ df_activity = activity_data.to_pandas()
258
+ df_activity["hour"] = pd.to_datetime(df_activity["hour"]) # Assurer le bon format datetime
259
+
260
+ # Tracer le graphique
261
+ fig = px.line(
262
+ df_activity,
263
+ x="hour",
264
+ y="connection_count",
265
+ markers=True, # Ajouter des points pour bien voir les pics
266
+ title="Hourly Connection Activity",
267
+ labels={"hour": "Hour", "connection_count": "Number of Connections"},
268
+ line_shape="spline" # Rendre les courbes lisses
269
+ )
270
+
271
+ # Afficher le graphique
272
+ st.plotly_chart(fig, use_container_width=True)
273
+ else:
274
+ st.info("No connection data found for the selected period.")
275
+ else:
276
+ st.warning("Column 'timestamp' not found.")
277
+
278
+
279
 
280
  # Onglet Foreign IP addresses
281
  with tab3:
282
+ st.subheader("🚫 List of access outside the university network")
283
+
284
+ if "ipsrc" in data.columns and "action" in data.columns:
285
+ # Conversion des IPs en chaînes de caractères pour éviter les erreurs de type
286
+ data = data.with_columns([
287
+ pl.col("ipsrc").cast(pl.Utf8).alias("ipsrc"),
288
+ pl.col("action").cast(pl.Utf8).alias("action")
289
+ ])
290
+
291
+ # Vérification des IPs avec la fonction is_university_ip
292
+ data = data.with_columns([
293
+ pl.col("ipsrc").map_elements(is_university_ip, return_dtype=pl.Boolean).alias("is_src_university_ip")
294
+ ])
295
+
296
+ # filtrer toutes les connexions impliquant une adresse externe
297
+ intrusion_attempts = data.filter(
298
+ (~pl.col("is_src_university_ip"))
299
+ )
300
+ # Ajout d'un filtre par action
301
+ selected_action = st.selectbox("Select action type", ["All", "PERMIT", "DENY"])
302
+
303
+ if selected_action != "All":
304
+ intrusion_attempts = intrusion_attempts.filter(
305
+ pl.col("action") == selected_action
306
+ )
307
+ # Affichage des accès externes
308
+ st.write(f"### 🔍 External accesses: {intrusion_attempts.shape[0]} entries")
309
+ st.dataframe( intrusion_attempts.drop(["is_src_university_ip"]), use_container_width=True)
310
+
311
+ else:
312
+ st.warning("Columns 'ipsrc' not found.")
313
+
314
+
315
 
316
  # Onglet Sankey
317
  with tab4: