%PDF- %PDF-
Direktori : /backups/router/usr/local/opnsense/mvc/app/views/OPNsense/Diagnostics/ |
Current File : //backups/router/usr/local/opnsense/mvc/app/views/OPNsense/Diagnostics/packetcapture.volt |
{# # Copyright (c) 2022 Deciso B.V. # All rights reserved. # # Redistribution and use in source and binary forms, with or withoutmodification, # are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY # AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, # OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. #} <style> .mac_selected { text-decoration: underline; font-weight: bolder; } .macfield { cursor: pointer; } .macinfo_header{ font-weight: bolder; } .tooltip-inner { max-width: 500px; } </style> <script> $( document ).ready(function() { let grid_jobs = $("#grid-jobs").UIBootgrid({ search:'/api/diagnostics/packet_capture/search_jobs', options:{ formatters: { "commands": function (column, row) { let btns = []; btns.push('<button type="button" data-toggle="tooltip" class="btn btn-xs btn-default command-remove" title="{{ lang._('remove capture') }}" data-row-id="' + row.id + '"><span class="fa fa-fw fa-remove"></span></button> '); if (row.status === 'stopped') { btns.push('<button type="button" data-toggle="tooltip" class="btn btn-xs btn-default command-start" title="{{ lang._('(re)start capture') }}" data-row-id="' + row.id + '"><span class="fa fa-fw fa-play"></span></button> '); } else if (row.status === 'running') { btns.push('<button type="button" data-toggle="tooltip" class="btn btn-xs btn-default command-stop" title="{{ lang._('stop capture') }}" data-row-id="' + row.id + '"><span class="fa fa-fw fa-stop"></span></button> '); } btns.push('<button type="button" data-toggle="tooltip" class="btn btn-xs btn-default command-download" title="{{ lang._('download capture') }}" data-row-id="' + row.id + '"><span class="fa fa-fw fa-cloud-download"></span></button> '); btns.push('<button type="button" data-toggle="tooltip" class="btn btn-xs btn-default command-view" title="{{ lang._('view capture (high detail)') }}" data-detail="high" data-row-id="' + row.id + '"><span class="fa fa-fw fa-file"></span></button> '); btns.push('<button type="button" data-toggle="tooltip" class="btn btn-xs btn-default command-view" title="{{ lang._('view capture (medium detail)') }}" data-detail="medium" data-row-id="' + row.id + '"><span class="fa fa-fw fa-file-text"></span></button> '); btns.push('<button type="button" data-toggle="tooltip" class="btn btn-xs btn-default command-view" title="{{ lang._('view capture') }}" data-detail="normal" data-row-id="' + row.id + '"><span class="fa fa-fw fa-file-o"></span></button> '); return btns.join(""); }, "status": function (column, row) { if (row.status == 'running') { return '<i class="fa fa-fw fa-spinner fa-pulse"></i>'; } else { return '<i class="fa fa-fw fa-stop-circle-o"></i>'; } } } } }); grid_jobs.on('loaded.rs.jquery.bootgrid', function() { $('[data-toggle="tooltip"]').tooltip(); $(".command-start").click(function(){ let id = $(this).data('row-id'); ajaxCall("/api/diagnostics/packet_capture/start/" + id, {}, function(){ $("#grid-jobs").bootgrid("reload"); }); }); $(".command-stop").click(function(){ let id = $(this).data('row-id'); ajaxCall("/api/diagnostics/packet_capture/stop/" + id, {}, function(){ $("#grid-jobs").bootgrid("reload"); }); }); $(".command-remove").click(function(){ let id = $(this).data('row-id'); ajaxCall("/api/diagnostics/packet_capture/remove/" + id, {}, function(){ $("#grid-jobs").bootgrid("reload"); }); }); $(".command-view").click(function(){ let id = $(this).data('row-id'); let detail = $(this).data('detail'); ajaxGet("/api/diagnostics/packet_capture/view/" + id + '/' + detail, {}, function(data){ if (data.interfaces !== undefined) { var html = []; $.each(data.interfaces, function(intf, data){ $.each(data['rows'], function(idx, line){ html.push( $("<tr>").append( $("<td>").append( $("<span>").text(data.name), $("<br>"), $("<small>").text(intf), ) ).append( $("<td>").append(line.timestamp.replace('T', '<br/>')) ).append( $("<td>").append( $("<span class='macfield' data-fam='"+line.fam+"' data-id='"+line.esrc+"'/>").text(line.esrc) ) ).append( $("<td>").append( $("<span class='macfield' data-fam='"+line.fam+"' data-id='"+line.edst+"'/>").text(line.edst) ) ).append( $("<td>").append( $("<span style='width:100%; word-break: break-word;'/>").html($("<code/>").html(line.raw)) ) ) ); }); }); $("#capture_output").empty().append(html); $("#pcapview").modal({}); $(".macfield").hover(function(){ let this_entry = $(this); let this_mac = $(this).data('id'); if (!$(this).hasClass("mac_info_fetched")) { $(this).addClass("mac_info_fetched"); ajaxGet("/api/diagnostics/packet_capture/mac_info/" + this_mac, {} , function(data){ if (data.status === 'ok') { $(".macfield").each(function(){ if (this_mac === $(this).data('id')) { $(this).addClass('mac_info_fetched'); let addresses = []; if (data[$(this).data('fam')]) { addresses = data[$(this).data('fam')]; } $(this).tooltip({ "html": true, "title": '<span class="macinfo_header">'+data.org+'</span><br/>' + addresses.join("<br/>") }); } }); this_entry.tooltip('show'); } }); } $(".macfield").each(function(){ if (this_mac === $(this).data('id')) { $(this).addClass('mac_selected'); } }); }, function(){ $(".macfield").removeClass('mac_selected'); $(".macfield").tooltip('hide') }); } }); }); $(".command-download").click(function(){ let id = $(this).data('row-id'); $('<a href="/api/diagnostics/packet_capture/download/'+id+'"></a>').get(0).click(); }); }); var data_get_map = {'frm_CaptureSettings':"/api/diagnostics/packet_capture/get"}; mapDataToFormUI(data_get_map).done(function(data){ formatTokenizersUI(); $('.selectpicker').selectpicker('refresh'); }); $("#btn_start_new").click(function () { if (!$("#frm_CaptureSettings_progress").hasClass("fa-spinner")) { $("#frm_CaptureSettings_progress").addClass("fa fa-spinner fa-pulse"); let callb = function (data) { $("#frm_CaptureSettings_progress").removeClass("fa fa-spinner fa-pulse"); if (data.result && data.result === 'ok') { ajaxCall("/api/diagnostics/packet_capture/start/" + data.uuid, {}, function(){ $("#capture_jobs_tab").click(); $("#grid-jobs").bootgrid("reload"); }); } } saveFormToEndpoint("/api/diagnostics/packet_capture/set", 'frm_CaptureSettings', callb, true, callb); } }); /** * Reformat static form items */ $("#btn_start_new > b").text("{{ lang._('Start') }}"); // (de)select all interfaces $(".interface_select").closest("td").find('a').remove(); $(".interface_select").closest("td").find('br').remove(); let btn_toggle_all = $('<button id="select_all" type="button" class="btn btn-default">'); btn_toggle_all.append($('<i class="fa fa-check-square-o fa-fw" aria-hidden="true"></i>')); btn_toggle_all.tooltip({"title": "{{ lang._('(de)select all') }}"}); btn_toggle_all.click(function(e){ e.preventDefault(); $(".interface_select option").prop("selected", $("#select_all > i").hasClass("fa-check-square-o")); $("#select_all > i").toggleClass("fa-check-square-o fa-square-o"); $(".interface_select").selectpicker('refresh'); }); $(".interface_select").closest("td").append(btn_toggle_all); }); </script> <ul class="nav nav-tabs" data-tabs="tabs" id="maintabs"> <li class="active"><a data-toggle="tab" href="#capture">{{ lang._('Capture') }}</a></li> <li><a data-toggle="tab" id="capture_jobs_tab" href="#capture_jobs">{{ lang._('Jobs') }}</a></li> </ul> <div class="tab-content content-box"> <div id="capture" class="tab-pane fade in active"> <div id="capture"> {{ partial("layout_partials/base_form",['fields':captureForm,'id':'frm_CaptureSettings', 'apply_btn_id':'btn_start_new'])}} </div> </div> <div id="capture_jobs" class="tab-pane fade in"> <table id="grid-jobs" class="table table-condensed table-hover table-striped table-responsive"> <thead> <tr> <th data-column-id="status" data-width="2em" data-sortable="false" data-formatter="status"> </th> <th data-column-id="id" data-type="string" data-sortable="false" data-identifier="true" data-visible="false">{{ lang._('ID') }}</th> <th data-column-id="description" data-type="string">{{ lang._('Description') }}</th> <th data-column-id="commands" data-width="15em" data-formatter="commands" data-sortable="false">{{ lang._('Commands') }}</th> </tr> </thead> <tbody> </tbody> </table> </div> </div> <!-- View capture (pcap) modal --> <div class="modal" tabindex="-1" role="dialog" id="pcapview"> <div class="modal-dialog" style="width: 90%;" role="document"> <div class="modal-content"> <div class="modal-header"> <div class="bootstrap-dialog-header"> <div class="bootstrap-dialog-close-button" style=""> <button class="close" class="close" data-dismiss="modal" aria-label="Close">×</button> </div> <div class="bootstrap-dialog-title"> <strong>{{ lang._('View capture') }}</strong> </div> </div> </div> <div class="modal-body"> <table class="table table-condensed"> <thead> <tr> <th>{{ lang._('Interface') }}</th> <th>{{ lang._('Timestamp') }}</th> <th>{{ lang._('SRC') }}</th> <th>{{ lang._('DST') }}</th> <th>{{ lang._('output') }}</th> </tr> </thead> <tbody style="white-space: pre-wrap; font-family: monospace;" id="capture_output"> </tbody> </table> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-dismiss="modal">{{ lang._('Close') }}</button> </div> </div> </div> </div>