package jfconfig; /** * Created : Mar 14, 2012 * * @author pquiring */ import java.io.*; import java.util.*; import javax.swing.*; import javax.swing.table.*; import javaforce.*; import javaforce.linux.*; public class RoutingPanel extends javax.swing.JPanel { /** * Creates new form RoutingPanel */ public RoutingPanel() { initComponents(); loadConfig(); showUserRoutes(); showActiveRoutes(); ConfigApp.This.setTitle("Config : Routing"); } /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always * regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { jToolBar1 = new javax.swing.JToolBar(); back = new javax.swing.JButton(); addRoute = new javax.swing.JButton(); edit = new javax.swing.JButton(); delRoute = new javax.swing.JButton(); save = new javax.swing.JButton(); apply = new javax.swing.JButton(); jLabel1 = new javax.swing.JLabel(); jLabel2 = new javax.swing.JLabel(); jScrollPane3 = new javax.swing.JScrollPane(); userTable = new javax.swing.JTable(); jScrollPane4 = new javax.swing.JScrollPane(); routesTable = new javax.swing.JTable(); delCurrentRoute = new javax.swing.JButton(); jToolBar1.setFloatable(false); jToolBar1.setRollover(true); back.setText("<Back"); back.setFocusable(false); back.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); back.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); back.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { backActionPerformed(evt); } }); jToolBar1.add(back); addRoute.setText("Add Route"); addRoute.setFocusable(false); addRoute.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); addRoute.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); addRoute.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { addRouteActionPerformed(evt); } }); jToolBar1.add(addRoute); edit.setText("Edit Route"); edit.setFocusable(false); edit.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); edit.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); edit.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { editActionPerformed(evt); } }); jToolBar1.add(edit); delRoute.setText("Delete Route"); delRoute.setFocusable(false); delRoute.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); delRoute.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); delRoute.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { delRouteActionPerformed(evt); } }); jToolBar1.add(delRoute); save.setText("Save"); save.setFocusable(false); save.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); save.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); save.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { saveActionPerformed(evt); } }); jToolBar1.add(save); apply.setText("Apply"); apply.setFocusable(false); apply.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); apply.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); apply.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { applyActionPerformed(evt); } }); jToolBar1.add(apply); jLabel1.setText("User Routes:"); jLabel2.setText("Current Active Routes:"); userTable.setModel(new javax.swing.table.DefaultTableModel( new Object [][] { }, new String [] { "Destination", "Netmask", "Flags", "Metric", "Gateway", "Interface" } ) { Class[] types = new Class [] { java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class }; boolean[] canEdit = new boolean [] { false, false, false, false, false, false }; public Class getColumnClass(int columnIndex) { return types [columnIndex]; } public boolean isCellEditable(int rowIndex, int columnIndex) { return canEdit [columnIndex]; } }); userTable.getTableHeader().setReorderingAllowed(false); jScrollPane3.setViewportView(userTable); userTable.getColumnModel().getSelectionModel().setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); routesTable.setModel(new javax.swing.table.DefaultTableModel( new Object [][] { }, new String [] { "Destination", "Netmask", "Flags", "Metric", "Gateway", "Interface" } ) { Class[] types = new Class [] { java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class }; boolean[] canEdit = new boolean [] { false, false, false, false, false, false }; public Class getColumnClass(int columnIndex) { return types [columnIndex]; } public boolean isCellEditable(int rowIndex, int columnIndex) { return canEdit [columnIndex]; } }); routesTable.getTableHeader().setReorderingAllowed(false); jScrollPane4.setViewportView(routesTable); routesTable.getColumnModel().getSelectionModel().setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); delCurrentRoute.setText("Delete Route"); delCurrentRoute.setFocusable(false); delCurrentRoute.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); delCurrentRoute.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); delCurrentRoute.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { delCurrentRouteActionPerformed(evt); } }); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jToolBar1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(jScrollPane3, javax.swing.GroupLayout.DEFAULT_SIZE, 530, Short.MAX_VALUE) .addComponent(jScrollPane4) .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addComponent(jLabel2) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(delCurrentRoute) .addGap(0, 0, Short.MAX_VALUE)) .addGroup(layout.createSequentialGroup() .addComponent(jLabel1) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addComponent(jToolBar1, javax.swing.GroupLayout.PREFERRED_SIZE, 25, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jLabel1) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jScrollPane3, javax.swing.GroupLayout.PREFERRED_SIZE, 243, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jLabel2) .addComponent(delCurrentRoute, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jScrollPane4, javax.swing.GroupLayout.DEFAULT_SIZE, 262, Short.MAX_VALUE)) ); }// </editor-fold>//GEN-END:initComponents private void backActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_backActionPerformed ConfigApp.setPanel(new NetworkPanel()); }//GEN-LAST:event_backActionPerformed private void addRouteActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addRouteActionPerformed addRoute(); }//GEN-LAST:event_addRouteActionPerformed private void delRouteActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_delRouteActionPerformed int idx = userTable.getSelectedRow(); if (idx == -1) return; delRoute(idx); }//GEN-LAST:event_delRouteActionPerformed private void saveActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveActionPerformed saveConfig(); }//GEN-LAST:event_saveActionPerformed private void applyActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_applyActionPerformed apply(); showActiveRoutes(); }//GEN-LAST:event_applyActionPerformed private void delCurrentRouteActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_delCurrentRouteActionPerformed int idx = routesTable.getSelectedRow(); if (idx == -1) return; delActiveRoute(idx); }//GEN-LAST:event_delCurrentRouteActionPerformed private void editActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_editActionPerformed int idx = userTable.getSelectedRow(); if (idx == -1) return; editRoute(idx); }//GEN-LAST:event_editActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton addRoute; private javax.swing.JButton apply; private javax.swing.JButton back; private javax.swing.JButton delCurrentRoute; private javax.swing.JButton delRoute; private javax.swing.JButton edit; private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabel2; private javax.swing.JScrollPane jScrollPane3; private javax.swing.JScrollPane jScrollPane4; private javax.swing.JToolBar jToolBar1; private javax.swing.JTable routesTable; private javax.swing.JButton save; private javax.swing.JTable userTable; // End of variables declaration//GEN-END:variables public static class Route { public String dest, mask, via; //via is "gw x.x.x." or "dev x" public int metric; } public static class Config { public Route route[]; } private Config config; private String configFolder = "/etc/jconfig.d/"; private String configFile = "routing.xml"; // private boolean dirty = false; private void loadConfig() { defaultConfig(); try { XML xml = new XML(); FileInputStream fis = new FileInputStream(configFolder + configFile); xml.read(fis); fis.close(); xml.writeClass(config); } catch (FileNotFoundException e1) { defaultConfig(); } catch (Exception e2) { JFLog.log(e2); defaultConfig(); } } private void defaultConfig() { config = new Config(); config.route = new Route[0]; } private void saveConfig() { try { XML xml = new XML(); File tmpFile = File.createTempFile("routing", ".xml"); FileOutputStream fos = new FileOutputStream(tmpFile); xml.readClass("routing", config); xml.write(fos); fos.close(); Linux.mkdir(configFolder); if (!Linux.copyFile(tmpFile.getAbsolutePath(), configFolder + configFile)) { tmpFile.delete(); throw new Exception("file io error"); } tmpFile.delete(); } catch (Exception e) { JFLog.log(e); } } private void showUserRoutes() { DefaultTableModel tm = (DefaultTableModel)userTable.getModel(); while (tm.getRowCount() > 0) { tm.removeRow(0); } for(int a=0;a<config.route.length;a++) { String via = config.route[a].via; String gw = "", iface = ""; if (via.startsWith("gw ")) gw = via.substring(3); if (via.startsWith("dev ")) iface = via.substring(4); tm.addRow(new Object[] {config.route[a].dest, config.route[a].mask, "", "" + config.route[a].metric, gw, iface}); } } private void showActiveRoutes() { //exec "route -n" and show in routes list DefaultTableModel tm = (DefaultTableModel)routesTable.getModel(); while (tm.getRowCount() > 0) { tm.removeRow(0); } try { ShellProcess sp = new ShellProcess(); ArrayList<String> cmd = new ArrayList<String>(); cmd.add("route"); cmd.add("-n"); String output = sp.run(cmd, false); if (output == null) throw new Exception("failed to exec route"); String lns[] = output.split("\n"); /* String headers = lns[1]; int destIdx = headers.indexOf("Dest"); int gwIdx = headers.indexOf("Gateway"); int maskIdx = headers.indexOf("Genmask"); int flagsIdx = headers.indexOf("Flags"); int metrixIdx = headers.indexOf("Metric"); //ignore Ref //ignore Use int ifIdx = headers.indexOf("Iface"); */ for(int a=2;a<lns.length;a++) { String f[] = lns[a].split(" +"); //space w/ greedy modifier tm.addRow(new Object[] {f[0], f[2], f[3], f[4], f[1], f[7]}); } } catch (Exception e) { JFLog.log(e); JF.showError("Error", "Failed to exec 'route'"); } } private void addRoute() { RoutingRouteDialog dialog = new RoutingRouteDialog(ConfigApp.This, true, null); dialog.setVisible(true); if (!dialog.accepted) return; Route route = new Route(); route.dest = dialog.getDest(); route.mask = dialog.getMask(); if (dialog.getUseDev()) route.via = "dev " + dialog.getDev(); else route.via = "gw " + dialog.getGw(); route.metric = dialog.getMetric(); config.route = Arrays.copyOf(config.route, config.route.length + 1); config.route[config.route.length-1] = route; showUserRoutes(); } private void editRoute(int idx) { Route route = config.route[idx]; RoutingRouteDialog dialog = new RoutingRouteDialog(ConfigApp.This, true, route); dialog.setVisible(true); if (!dialog.accepted) return; route.dest = dialog.getDest(); route.mask = dialog.getMask(); if (dialog.getUseDev()) route.via = "dev " + dialog.getDev(); else route.via = "gw " + dialog.getGw(); route.metric = dialog.getMetric(); showUserRoutes(); } private void delRoute(int idx) { if (!JF.showConfirm("Confirm", "Are you sure you want to delete?")) return; int len = config.route.length; Route newList[] = new Route[len-1]; System.arraycopy(config.route, 0, newList, 0, idx); System.arraycopy(config.route, idx+1, newList, idx, len - idx - 1); config.route = newList; showUserRoutes(); } private void delActiveRoute(int idx) { DefaultTableModel tm = (DefaultTableModel)routesTable.getModel(); try { ShellProcess sp = new ShellProcess(); ArrayList<String> cmd = new ArrayList<String>(); cmd.add("sudo"); cmd.add("route"); cmd.add("del"); cmd.add("-net"); cmd.add((String)tm.getValueAt(idx, 0)); cmd.add("netmask"); cmd.add((String)tm.getValueAt(idx, 1)); sp.run(cmd, false); if (sp.getErrorLevel() != 0) throw new Exception("failed to exec route"); } catch (Exception e) { JFLog.log(e); JF.showError("Error", "Failed to exec 'route'"); } showActiveRoutes(); } private String applyRoute(Route route) { StringBuilder cmd = new StringBuilder(); cmd.append("route add -net "); cmd.append(route.dest); cmd.append(" netmask "); cmd.append(route.mask); cmd.append(" "); int idx = route.via.indexOf(" "); cmd.append(route.via.substring(0, idx)); cmd.append(" "); cmd.append(route.via.substring(idx+1)); if (route.metric > 0) { cmd.append(" metric "); cmd.append(route.metric); } cmd.append("\n"); return cmd.toString(); } private void apply() { saveConfig(); //save to /etc/jconfig.d/routing.sh try { File tmpFile = File.createTempFile("routing", ".sh"); FileOutputStream fos = new FileOutputStream(tmpFile); fos.write("#!/bin/bash\n".getBytes()); for(int a=0;a<config.route.length;a++) { fos.write(applyRoute(config.route[a]).getBytes()); } fos.close(); if (!Linux.copyFile(tmpFile.getAbsolutePath(), "/etc/jconfig.d/routing.sh")) { tmpFile.delete(); throw new Exception("file io error"); } tmpFile.delete(); if (!Linux.setExec("/etc/jconfig.d/routing.sh")) { throw new Exception("file io error"); } } catch (Exception e) { JFLog.log(e); JF.showError("Error", "Failed to save rules to /etc/jconfig.d/routing.sh"); return; } //exec /etc/jconfig.d/routing.sh to apply now try { ShellProcess sp = new ShellProcess(); sp.run(new String[] {"sudo", "/etc/jconfig.d/routing.sh"}, false); if (sp.getErrorLevel() != 0) throw new Exception("routing failed"); } catch (Exception e) { JFLog.log(e); JF.showError("Error", "Failed to exec /etc/jconfig.d/routing.sh"); return; } //add /etc/jconfig.d/routing.sh to /etc/rc.local for next reboot try { FileInputStream fis = new FileInputStream("/etc/rc.local"); byte data[] = JF.readAll(fis); String str = new String(data); String lns[] = str.split("\n"); int exitIdx = -1; for(int a=0;a<lns.length;a++) { if (lns[a].startsWith("exit ")) exitIdx = a; if (lns[a].indexOf("/etc/jconfig.d/routing.sh") != -1) { //already done JF.showMessage("Notice", "Routing table updated!"); return; } } File tmpFile = File.createTempFile("rc_local", ".tmp"); FileOutputStream fos = new FileOutputStream(tmpFile); for(int a=0;a<lns.length;a++) { if (a == exitIdx) { fos.write("/etc/jconfig.d/routing.sh\n".getBytes()); } fos.write(lns[a].getBytes()); fos.write("\n".getBytes()); } if (exitIdx == -1) { fos.write("/etc/jconfig.d/routing.sh\n".getBytes()); } fos.close(); if (!Linux.copyFile(tmpFile.getAbsolutePath(), "/etc/rc.local")) { tmpFile.delete(); throw new Exception("file io error"); } if (!Linux.setExec("/etc/rc.local")) { tmpFile.delete(); throw new Exception("file io error"); } tmpFile.delete(); } catch (Exception e) { JFLog.log(e); JF.showError("Error", "Failed to add routing.sh to /etc/rc.local"); return; } JF.showMessage("Notice", "Routing table updated!"); } }