BiTel

Форум BiTel
bgbilling.ru     docs.bitel.ru     wiki.bitel.ru     dbinfo.bitel.ru     bgcrm.ru     billing.bitel.ru     bitel.ru    
Текущее время: 29 мар 2024, 18:07

Часовой пояс: UTC + 5 часов [ Летнее время ]




Начать новую тему Ответить на тему  [ Сообщений: 21 ] 
Автор Сообщение
 Заголовок сообщения: Mikrotik API Client
СообщениеДобавлено: 01 апр 2011, 18:10 
Не в сети

Зарегистрирован: 15 авг 2009, 21:04
Сообщения: 41
Откуда: Казахстан
Карма: 10
Вывожу свои скрипты для работы с микротиком через API.

Библиотека mikrotik. Оригинальный автор классов - некто Яниск, я же переделал их на BeanShell и добавил пару классов для удобства.

Код:
import java.io.*;
import java.net.*;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays.copyOf;

/**
*
* @orginal author janisk
*/
public class Hasher {
 
  /**
  * makes MD5 hash of string for use with RouterOS API
  * @param s - variable to make hacsh from
  * @return
  */
  static public String hashMD5(String s) {
    String md5val = "";
    MessageDigest algorithm = null;
    int i;
    try {
      algorithm = MessageDigest.getInstance("MD5");
    } catch (NoSuchAlgorithmException nsae) {
      System.out.println("Cannot find digest algorithm");
      System.exit(1);
    }
    byte[] defaultBytes = new byte[s.length()];
    for (i = 0; i < s.length(); i++) {
      defaultBytes[i] = (byte) (0xFF & s.charAt(i));
    }
    algorithm.reset();
    algorithm.update(defaultBytes);
    messageDigest = algorithm.digest();
    StringBuffer hexString = new StringBuffer();
    for (i = 0; i < messageDigest.length; i++) {
      String hex = Integer.toHexString(0xFF & messageDigest[i]);
      if (hex.length() == 1) {
        hexString.append('0');
      }
      hexString.append(hex);
    }
    return hexString.toString();
  }
 
  /**
  * converts hex value string to normal string for use with RouterOS API
  * @param s - hex string to convert to
  * @return - converted string.
  */
  static public String hexStrToStr(String s) {
    String ret = "";
    for (int i = 0; i < s.length(); i += 2) {
      ret += (char) Integer.parseInt(s.substring(i, i + 2), 16);
    }
    return ret;
  }
}



public class ReadCommand implements Runnable {
 
  private DataInputStream in = null;
  private LinkedBlockingQueue queue = null;
 
  /**
  * Creates a new instance of CommandRead
  * @param in - Data input stream of socket
  * @param queue - data output inteface
  */
  public ReadCommand(DataInputStream in, LinkedBlockingQueue queue) {
    this.in = in;
    this.queue = queue;
  }
 
 
  public void run() {
    byte b = 0;
    String s = "";
    char ch;
    int sk, i, a = 0;
    while (true) {
      //int sk = 0;
      try {
        a = in.readByte();
      } catch (IOException ex) {
        return;
      }
      if (a != 0 && a > 0) {
        if (a < 0x80) {
          sk = a;
        } else {
          if (a < 0xC0) {
            a = a << 8;
            try {
              a += in.readByte();
            } catch (IOException ex) {
              return;
            }
            sk = a ^ 0x8000;
          } else {
            if (a < 0xE0) {
              try {
                for (i = 0; i < 2; i++) {
                  a = a << 8;
                  a += in.readByte();
                }
              } catch (IOException ex) {
                Logger.getLogger(ReadCommand.class.getName()).log(Level.SEVERE, null, ex);
                return;
              }
              sk = a ^ 0xC00000;
            } else {
              if (a < 0xF0) {
                try {
                  for (i = 0; i < 3; i++) {
                    a = a << 8;
                    a += in.readByte();
                  }
                } catch (IOException ex) {
                  Logger.getLogger(ReadCommand.class.getName()).log(Level.SEVERE, null, ex);
                  return;
                }
                sk = a ^ 3758096384L;
              } else {
                if (a < 0xF8) {
                  try {
                    a = 0;
                    for (i = 0; i < 5; i++) {
                      a = a << 8;
                      a += in.readByte();
                    }
                  } catch (IOException ex) {
                    Logger.getLogger(ReadCommand.class.getName()).log(Level.SEVERE, null, ex);
                    return;
                  }
                } else {
                }
              }
            }
          }
        }
        s += "\n";
        byte[] bb = new byte[sk];
        try {
          a = in.read(bb, 0, sk);
        } catch (IOException ex) {
          a = 0;
          ex.printStackTrace();
          return;
        }
        if (a > 0) {
          s += new String(bb);
        }
      } else if (b == -1) {
        System.out.println("Error, it should not happen ever, or connected to wrong port");
      } else {
        try {
          queue.put(s);
        } catch (InterruptedException ex) {
          ex.printStackTrace();
          System.out.println("exiting reader");
          return;
        }
        s = "";
      }
    }
  }
}


public class WriteCommand {
 
  private byte[] len = {0};
  private DataOutputStream out = null;
  private String command = "";
 
  WriteCommand(DataOutputStream out, String command) {
    this.out = out;
    this.command = command.replaceAll("\n", "").trim();
  }
 
  WriteCommand(DataOutputStream out) {
    this.out = out;
  }
 
  public void setCommand(String command) {
    this.command = command.trim();
    //return this;
  }
 
  String getCommand() {
    return command;
  }
 
  private byte[] writeLen(String command) {   
    Integer i = null;
    String s = "";
    String ret = "";
    if (command.length() < 0x80) {
      i = command.length();
    } else if (command.length() < 0x4000) {
      i = Integer.reverseBytes(command.length() | 0x8000);
    } else if (command.length() < 0x20000) {
      i = Integer.reverseBytes(command.length() | 0xC00000);
    } else if (command.length() < 10000000) {
      i = Integer.reverseBytes(command.length() | 3758096384L);
    } else {
      i = Integer.reverseBytes(command.length());
    }
    s = Integer.toHexString(i);   
    if (s.length() < 2) {     
      return new byte[]{i.byteValue()};
    } else {
      for (int j = 0; j < s.length(); j += 2) {
        ret += (char) Integer.parseInt(s.substring(j, j + 2), 16) != 0 ? (char) Integer.parseInt(s.substring(j, j + 2), 16) : "";
      }
    }
    //char[] ch = ret.toCharArray();
    return ret.getBytes();
  }
 
  String runCommand() {
    int i, a, j;
    int counter;
    byte[] ret = new byte[0];
    try {
      if (!command.contains("\n")) {
        byte[] b = writeLen(command);
        int retLen = b.length + command.length() + 1;
        ret = (byte[])Arrays.copyOf(ret, retLen);
        for (i = 0; i < b.length; i++) {
          ret[i] = b[i];
        }
        //System.arraycopy(b, 0, ret, 0, b.length);
        //i = b.length;
        for (byte c : command.getBytes()) { //"US-ASCII"
          ret[i] = c;
          i = i + 1;
        }
      } else {
        String[] str = command.split("\n");
        i = 1;
        int[] iTmp = new int[str.length];       
        for (a = 0; a < str.length; a++) {
          iTmp[a] = writeLen(str[a]).length + str[a].length();
        }
        for (int b : iTmp) {         
          i += b;
        }
        ret = (byte[])Arrays.copyOf(ret, i);
        counter = 0;
        for (a = 0; a < str.length; a++) {
          byte[] b = writeLen(str[a]);
          for (j = 0; j < b.length; j++) {
            ret[counter] = b[j];
            counter = counter + 1;
          }
          for (byte c : str[a].getBytes()) { //"US-ASCII"
            ret[counter] = c;
            counter = counter + 1;
          }
        }
      }
      /*for(i = 0; i < ret.length; i++) {
        print(i.toString() + " : " + ret[i].toString());
      }*/
      out.write(ret, 0, ret.length);
      return "Sent successfully";
    } catch (IOException ex) {
      Logger.getLogger(WriteCommand.class.getName()).log(Level.SEVERE, null, ex);
      return "failed";
    }
  }
}


public class ApiConn /*extends Thread*/ {
 
  private Socket sock = null;
  private DataOutputStream out = null;
  private DataInputStream in = null;
  private String ipAddress;
  private int ipPort;
  private boolean connected = false;
  private String message = "Not connected";
  private ReadCommand readCommand = null;
  private WriteCommand writeCommand = null;
  private Thread listener = null;
  private LinkedBlockingQueue queue = new LinkedBlockingQueue(40);
 
  /**
  * Constructor of the connection class
  * @param ipAddress - IP address of the router you want to conenct to
  * @param ipPort - port used for connection, ROS default is 8728
  */
  public ApiConn(String ipAddress, int ipPort) {
    this.ipAddress = ipAddress;
    this.ipPort = ipPort;
    //this.setName("settings");
  }
 
  /**
  * State of connection
  * @return - if connection is established to router it returns true.
  */
  public boolean isConnected() {
    return connected;
  }
  public void disconnect() throws IOException{
    listener.interrupt();
    sock.close();
  }
  public void listen() {
    if (this.isConnected()) {
      if (readCommand == null) {
        readCommand = new ReadCommand(in, queue);
      }
      listener = new Thread(readCommand);
      listener.setDaemon(true);
      listener.setName("listener");
      listener.start();
    }
  }
 
  /**
  * to get IP address of the connection. Reads data from socket created.
  * @return InetAddress
  */
  public InetAddress getIpAddress() {
    return sock == null ? null : sock.getInetAddress();
  }
 
  /**
  * returns ip address that socket is asociated with.
  * @return InetAddress
  */
  public InetAddress getLocalIpAddress() {
    return sock == null ? null : sock.getLocalAddress();
  }
 
  /**
  * Socket remote port number
  * @return
  */
  public int getPort() {
    return sock == null ? null : sock.getPort();
  }
 
  /**
  * return local prot used by socket
  * @return
  */
  public int getLocalPort() {
    return sock == null ? null : sock.getLocalPort();
  }
 
  /**
  * Returns status message set up bu class.
  * @return
  */
  public String getMessage() {
    return message;
  }
 
  /**
  * sets and exectues command (sends it to RouterOS host connected)
  * @param s - command will be sent to RouterOS for example "/ip/address/print\n=follow="
  * @return
  */
  public String sendCommand(String s) {
    writeCommand.setCommand(s);
    return writeCommand.runCommand();
  }
 
  /**
  * exeecutes already set command.
  * @return returns status of the command sent
  */
  public String runCommand() {
    return writeCommand.runCommand();
  }
 
  /**
  * Tries to fech data that is repllied to commands sent. It will wait till it can return something.
  * @return returns data sent by RouterOS
  * @throws java.lang.InterruptedException
  */
  public String getData() throws InterruptedException {
    String s = (String) queue.take();
    return s;
  }
 
  /**
  * returns command that is set at this moment. And will be exectued if runCommand is exectued.
  * @return
  */
  public String getCommand() {
    return writeCommand.getCommand();
  }
 
  /**
  * set up method that will log you in
  * @param name - username of the user on the router
  * @param password - password for the user
  * @return
  */
  public String login(String name, String password) {
    this.sendCommand("/login");
    String s = "a";
    String[] tmp;
    try {
      s = this.getData();
    } catch (InterruptedException ex) {
      Logger.getLogger(ApiConn.class.getName()).log(Level.SEVERE, null, ex);
      return "failed read #1";
    }
    if (!s.contains("!trap") && s.length() > 4) {
      tmp = s.trim().split("\n");
      if (tmp.length > 1) {
        tmp = tmp[1].split("=ret=");
        s = "";
        String transition = tmp[tmp.length - 1];
        String chal = "";
        chal = Hasher.hexStrToStr("00") + password + Hasher.hexStrToStr(transition);
        chal = Hasher.hashMD5(chal);
        String m = "/login\n=name=" + name + "\n=response=00" + chal;
        s = this.sendCommand(m);
        try {
          s = this.getData();
        } catch (InterruptedException ex) {
          Logger.getLogger(ApiConn.class.getName()).log(Level.SEVERE, null, ex);
          return "failed read #2";
        }
        if (s.contains("!done")) {
          if (!s.contains("!trap")) {
            return "Login successful";
          }
        }
      }
    }
    return "Login failed";
  }

  public void run() {
    try {
      InetAddress ia = InetAddress.getByName(ipAddress);
      if (ia.isReachable(1000)) {
        sock = new Socket(ipAddress, ipPort);
        in = new DataInputStream(sock.getInputStream());
        out = new DataOutputStream(sock.getOutputStream());
        connected = true;
        readCommand = new ReadCommand(in, queue);
        writeCommand = new WriteCommand(out);
        this.listen();
        message = "Connected";
      } else {
        message = "Not reachable";
      }
    } catch (UnknownHostException ex) {
      connected = false;
      message = ex.getMessage();
      ex.printStackTrace();
    } catch (IOException ex) {
      connected = false;
      message = ex.getMessage();
      ex.printStackTrace();
    }
  }
}

public class ApiAnswer {
  private String[] Text;
 
  public ApiAnswer() {};
  public ApiAnswer(String data) {
    Text = data.split("\n");
  }
 
  public change(String data) {
    Text = data.split("\n");
  }
 
  public String getParam(String param) {
    String[] tmp;
    String line;
    for(line: Text) {
      if (line.contains(param)) {
        tmp = line.split(param);
        if (tmp.length > 1) {
          return tmp[tmp.length - 1];
        }
        else return "";
      }
    }
    return "";
  }
 
  public boolean isError() {
    String line;
    for (line: Text) {
      if (line.contains("!trap"))
        return true;
    }
    return false;
  }
 
  public boolean isDone() {
    String line;
    for (line: Text) {
      if (line.contains("!done"))
        return true;
    }
    return false;
  }
 
  public String[] getText() {
    return Text;
  }
}

public class ApiCommand {
  private String Text;
 
  public ApiCommand() {
    Text = "";
  }
 
  public void clear() {
    Text = "";
  }
 
  public void add(String line) {
    if(Text.length() == 0) {
      Text = line;
    }
    else {
      Text = Text + "\n" + line;
    }
  }
 
  public String getText() {
    return Text;
  }
}


И мой пример ее использования. Скрипт для шлюза Микротик с использованием выборки типа правил из вики.

Код:
import java.util.*;
import java.util.regex.*;
import java.text.*;
import java.sql.*;

import ru.bitel.bgbilling.common.*;
import bitel.billing.common.module.ipn.*;
import bitel.billing.server.contract.bean.*;
import bitel.billing.server.ipn.bean.*;
import bitel.billing.server.ipn.*;
import bitel.billing.server.util.*;

//import bitel.billing.common.KernelConst;

includeBGBS("bgbs://ru.bitel.bgbilling.kernel.script.common.bean.ScriptLibrary/mikrotik");


private getNewRule(status)
{
   SERVICE_INTERNET = 27;
   SERVICE_INTRANET = 29;
  //   if (status.ruleType == null){
    //      return;
  //   };
  H = new Hashtable();
  H.put("operation", "get_ipn_rule_id");
  H.put("cid", status.contractId);
  H.put("mid", status.mid);
  H.put("sid", SERVICE_INTERNET);
  H.put("time", new GregorianCalendar());
  ParseTarif(H);
  rule_id = H.get("rule_id");
  //rule_id = 1;
  if (rule_id != null)
  {
    rule_type_manager = new RuleTypeManager(con,status.mid);
    status.ruleType = rule_type_manager.getType(Integer.parseInt(rule_id));
     return status;
  }
   else return null;
}

private void ParseTarif(H)
{
  H.put("is_found", false);
  cid = H.get("cid");
  if (cid == null)
  {
    return;
  };
  time = H.get("time");
  if (time == null)
  {
    return;
  };
  formatter = new SimpleDateFormat("yyyy-MM-dd");
  tarif_date = formatter.format(time.getTime()).toString();
 
  query = "SELECT contract_tree_link.tree_id "+
  "FROM contract_tree_link "+
  "WHERE "+
  "(contract_tree_link.date1 is NULL OR contract_tree_link.date1<='"+tarif_date+"') AND "+
  "(contract_tree_link.date2 is NULL OR contract_tree_link.date2>='"+tarif_date+"') AND "+
  "contract_tree_link.cid='"+cid+"' "+
  "UNION "+
  "SELECT tariff_tree_link.tree_id "+
  "FROM contract_tariff "+
  "  INNER JOIN tariff_tree_link "+
  "  ON (contract_tariff.tpid=tariff_tree_link.tpid) "+
  "WHERE (contract_tariff.date1 is NULL OR contract_tariff.date1<='"+tarif_date+"') AND "+
  "(contract_tariff.date2 is NULL OR contract_tariff.date2>='"+tarif_date+"') AND "+
  "contract_tariff.cid='"+cid+"'";
  re = con.prepareStatement(query);
  rs = re.executeQuery();
  while (rs.next())
  {
    tree_id = rs.getString(1);
    ParseMTree(tree_id,H);
  };
}

private void ParseMTree(tree_id,H)
{   
  is_found = H.get("is_found");
  if (is_found == null)
  {
    return;
  };
  if (is_found)
  {
    return;
  };
  mid = H.get("mid");
  if (mid == null)
  {
    return;
  };
  query = "SELECT mtree_node.id "+
  "FROM module_tariff_tree "+
  "  INNER JOIN mtree_node "+
  "  ON (module_tariff_tree.id=mtree_node.mtree_id) "+
  "WHERE mtree_node.type='root' AND module_tariff_tree.tree_id='"+tree_id+"' AND module_tariff_tree.mid='"+mid+"'";
  re = con.prepareStatement(query);
  rs = re.executeQuery();
  while (rs.next())
  {
    node_id = rs.getString(1);
    ParseNode(node_id,H);
  };
}

private void ParseNode(node_id,H)
{
  is_found = H.get("is_found");
  if (is_found == null)
  {
    return;
  };
  if (is_found)
  {
    return;
  };
  sid = H.get("sid");
  if (sid == null)
  {
    return;
  };
  operation = H.get("operation");
  if (operation == null)
  {
    return;
  };
  time = H.get("time");
  if (time == null)
  {
    return;
  };
  query = "SELECT id, type, data FROM mtree_node WHERE parent_node='"+node_id+"'";
  re = con.prepareStatement(query);
  rs = re.executeQuery();
  while (rs.next())
  {
    id = rs.getString(1);
    type = rs.getString(2);
    data = rs.getString(3);
    if (type.equals("service") && sid != Integer.parseInt(data))
    {
      continue;
    };
    if (type.equals("ipn_rule") && operation.equals("get_ipn_rule_id"))
    {
      datas = data.split ("&");
      H.put("rule_id",datas[1]);
      H.put("is_found",true);
    };
    if (type.equals("period"))
    {
      datas = data.split ("%");
      date1 = null;
      date2 = null;
      for (i=0; i<datas.length; i++)
      {
        date_arr = datas[i].split("&");
        if (date_arr.length != 2)
        {
          continue;
        };
        formatter = new SimpleDateFormat("dd.MM.yyy");
        date = formatter.parse(date_arr[1]);
        if (date_arr[0].equals("date1"))
        {
          date1 = date;
        };
        if (date_arr[0].equals("date2"))
        {
          date2 = date;
        };
      };
      if (date1 != null && date1.compareTo(time.getTime()) != -1){
        continue;
      };
      if (date2 != null && date2.compareTo(time.getTime()) != 1){
        continue;
      };
    };
    ParseNode(id,H);
  };
};


protected void doSync()
{
   host = gate.getHost();
   port = gate.getPort();
   gateSetup = new DefaultServerSetup( gate.getConfig(), "\r\n" );
   login = gateSetup.getStringValue( "login", "root" );                               
   timeout = gateSetup.getIntValue( "timeout", 2000 );
   pswd = gate.getKeyword();
 
  ApiAnswer answer = new ApiAnswer();
  ApiCommand command = new ApiCommand();
  String str, lastRes, idList;
  boolean newIdList;
  String commandMark = "#";
  ApiConn conn = new ApiConn(host, port);
  conn.run();
  if (conn.isConnected()) {
    print(conn.login(login, pswd));
    if ( log.isDebugEnabled() )
    {
      log.info( " gate: " + host + ":" + port + " login: " + login + " pswd: " + pswd );
    }
    session = null;
    try
    {
      command_list = null;
     
      for ( UserStatus status : statusList )
      {
        cid = status.contractId;
        status = getNewRule(status);
        ruleType = status.ruleType;
       
        if (ruleType != null)
        {
          rule_id = ruleType.getId();
        }
        else {
          rule_id = 0;
        };
       
        rules = null;
        if ( status.status == IPNContractStatus.STATUS_OPEN )
        {
          //открываем
          rules = getOpenRules( status );
          log.info("OpenRules !!"+cid+"!!");
        }
        else {
          if ( status.status == IPNContractStatus.STATUS_REMOVED )
          {
            // удаляем
            rules = getDeleteRules( status );
            log.info("DeleteRules !!"+cid+"!!");
          }
          else
          {
            // закрываем
            rules = getCloseRules( status );
            log.info("CloseRules !!"+cid+"!!");
          };
        };
       
        if (rules != null)
        {
          lastRes = "";
          idList = "";
          for ( String rule : rules )
          if (rule.length() > 0) {
            if((rule.indexOf(commandMark) == 0)&&(command.getText().length() > 0)) {
              print(command.getText());
              print(conn.sendCommand(command.getText()));
              print("*****");
              newIdList = true;
              do {
                str = conn.getData();
                print(str);
                answer.change(str);
                command.clear();
                if(answer.isError()) {
                  print("error");
                  //str = conn.getData();
                  //print(str);
                }
                if(answer.getParam("=ret=").length() > 0) {
                  lastRes = answer.getParam("=ret=");
                  //print("result=" + lastRes);
                }
                if(answer.getParam("=.id=").length() > 0) {
                  if (newIdList) {
                    idList = answer.getParam("=.id=");
                    newIdList = false;
                  }
                  else {
                    idList = idList + "," + answer.getParam("=.id=");
                  }
                }
              } while (!answer.isDone());
              print("\n");
            }
            else {
              str = rule;
              str = str.replaceAll("\\{RESULT\\}", lastRes);
              str = str.replaceAll("\\{LIST\\}", idList);
              command.add(str);
            };
          }
        }
        else print("no rules");
      }
    }
    catch( Exception e )
    {
      throw new RuntimeException( e );
    }
    finally
    {
      if ( conn.isConnected() )
      {
        conn.disconnect();
      }
    }
  }
  else throw new RuntimeException("Cannot connect to router");
}

private getOpenRules( status )
{
  return getRules( status, "\\[OPEN\\](.*)\\[/OPEN\\]" );
}

private getCloseRules( status )
{
  return getRules( status, "\\[CLOSE\\](.*)\\[/CLOSE\\]" );
}

private getDeleteRules( status )
{
  return getRules( status, "\\[DELETE\\](.*)\\[/DELETE\\]" );
}   

private getRules( status, template )
{
  // пользовательское правило, без типа - то все оставляем как есть
  String ruleText = ManadUtils.getRule( status.gateType, status.ruleType );
 
  //получаем списки адресов для данного клиента на текущий момент
  now = new java.util.GregorianCalendar();
  ARM = new AddressRangeManager( con, status.mid);
  addressList = ARM.getContractAddressRange(status.contractId, now, 0);
  for (addressRange: addressList) {
    pool = addressRange.toShortString(); //приводим к нужному формату
  }
  pool = pool.replace(" ", "");
 
  //получаем номер влана для клиента
  VLANID_PID = 9;
  CPM = new ContractParameterManager( con );
  vlanid = CPM.getStringParam(status.contractId, VLANID_PID);
 
 
  // типизированное правило
  if ( status.ruleType != null )
  {
    rule = generateRule( pool, status.gateType, status.ruleType, status.contractId, vlanid );
  }
  else
  {
    rule = status.rule.getRuleText();
  }
  pattern = Pattern.compile( template, Pattern.DOTALL );
  m = pattern.matcher( rule );
  if ( m.find() )
  {
    rule = m.group( 1 );
  }
  rule.replaceAll( "\r", "" );
  parts = rule.split( "\n" ); //приводим к нужному формату
 
  result = new ArrayList();
  for ( String part : parts )
  {
    if ( !Utils.isEmptyString( part ))
    {
      result.add( part );
    }
  }
 
  return result;
  //   return rule.split( "\n" );
}

private   generateRule( pool, gateType, ruleType, cid, vlanid )
{
  String rule;
  String ruleTypeData = ruleType.getData();
 
  ruleTypeData.replaceAll("\r", "");
  templates = ruleTypeData.split("\n");
  ruleText = ManadUtils.getRule( gateType, ruleType );
  replacements = new HashMap();
  replacements.put( "\\{CID\\}", String.valueOf( cid ) );
  replacements.put( "\\{VID\\}", String.valueOf( vlanid ) );
  replacements.put( "\\{POOL\\}", pool );
  //делаем подстановку макросов из текущего типа правила.
  for(String template : templates) {
    splitter = template.indexOf("=");
    key = template.substring(0, splitter - 1); //имя макроса
    value = template.substring(splitter + 1, template.length() - 1); //значение
    replacements.put("$\\{"+key+"\\}", value);
  };
  addresses = "";
  rule = ManadUtils.generateRule( ruleText, addresses, replacements, ruleType );
  return rule;
}



Мне пришлось эмулировать работу команды find в виде отдельных макросов подстановки: {RESULT} - результат выполнения последней команды; {LIST} - список элементов, выданный последней командой.
Другие макросы: {POOL} - выданный клиенту пул адресов, {VID} - введенный вручную номер влана, {CID} - номер договора.
Команды для скриптового шлюза:
Код:
[DEFAULT]
[OPEN]
/ip/firewall/address-list/print
?=address={POOL}
?=list=closed_clients
#
/ip/firewall/address-list/remove
=numbers={LIST}
#
/queue/simple/add
=name=vlan{VID}
=interface=vlan{VID}
=limit-at=${upload}/${download}
=max-limit=${upload}/${download}
=disabled=no
#
[/OPEN]

[CLOSE]
/ip/firewall/address-list/add
=address={POOL}
=list=closed_clients
=comment=!!{CID}!!
#
/queue/simple/remove
=numbers=vlan{VID}
#
[/CLOSE]

[DELETE]
/ip/firewall/address-list/add
=address={POOL}
=list=closed_clients
=comment=!!{CID}!!
#
/queue/simple/remove
=numbers=vlan{VID}
#
[/DELETE]
[/DEFAULT]



Все команды отлично работают в версии биллинга 4.6 и должны работать в 5.0.

_________________
Arbeit macht frei


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Mikrotik API Client
СообщениеДобавлено: 01 апр 2011, 18:17 
Не в сети

Зарегистрирован: 15 авг 2009, 21:04
Сообщения: 41
Откуда: Казахстан
Карма: 10
Имеется ряд преимуществ по отношению к телнетовскому клиенту, такие как более высокая скорость работы, большая надежность. Самым же главным отличием является положительная обратная связь - можно отслеживать реакцию на свои команды. И сам ответ микротика более машинно-ориентирован, в нем нет никаких лишних символов форматирования и нет такой несуразицы как три приглашения к вводу от одной команды и ни одного - от другой.

_________________
Arbeit macht frei


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Mikrotik API Client
СообщениеДобавлено: 03 апр 2011, 16:13 
Не в сети
Клиент

Зарегистрирован: 12 фев 2008, 18:10
Сообщения: 3951
Карма: 249
перенесите все в вики и напишите там "тема для обсуждения" (ссылка на эту тему) - так код будет в одном месте (более подходящем для этого, IMHO), а обсуждение в другом ;)


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Mikrotik API Client
СообщениеДобавлено: 05 апр 2011, 16:50 
Не в сети
Разработчик

Зарегистрирован: 08 ноя 2007, 01:05
Сообщения: 8343
Откуда: Уфа
Карма: 238
сделал ссылку сюда:
http://wiki.bgbilling.ru/index.php/%D0% ... API_Client


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Mikrotik API Client
СообщениеДобавлено: 05 апр 2011, 16:59 
Не в сети
Клиент

Зарегистрирован: 12 фев 2008, 18:10
Сообщения: 3951
Карма: 249
"работающий по Mikrotik API"? может все же лучше "работающий через Mikrotik API" или "работающий с помощью Mikrotik API"?


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Mikrotik API Client
СообщениеДобавлено: 05 апр 2011, 17:11 
Не в сети
Разработчик

Зарегистрирован: 08 ноя 2007, 01:05
Сообщения: 8343
Откуда: Уфа
Карма: 238
snark писал(а):
"работающий по Mikrotik API"? может все же лучше "работающий через Mikrotik API" или "работающий с помощью Mikrotik API"?

fixed


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Mikrotik API Client
СообщениеДобавлено: 05 апр 2011, 17:12 
Не в сети
Разработчик

Зарегистрирован: 08 ноя 2007, 01:05
Сообщения: 8343
Откуда: Уфа
Карма: 238
а вот это похоже первоисточник :

http://wiki.mikrotik.com/wiki/API_in_Java


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Mikrotik API Client
СообщениеДобавлено: 08 апр 2011, 13:41 
Не в сети

Зарегистрирован: 15 авг 2009, 21:04
Сообщения: 41
Откуда: Казахстан
Карма: 10
stark писал(а):
а вот это похоже первоисточник :

http://wiki.mikrotik.com/wiki/API_in_Java


Так и есть.

_________________
Arbeit macht frei


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Mikrotik API Client
СообщениеДобавлено: 11 апр 2011, 15:21 
Не в сети

Зарегистрирован: 02 июл 2009, 08:40
Сообщения: 22
Карма: 0
Уважаемый akubik!
Не могли бы Вы описать детальнее процедуру создания рабочего шлюза? По какому сетевому протоколу (если он есть) общается биллинг с микротиком посредством скрипта и т.д.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Mikrotik API Client
СообщениеДобавлено: 14 апр 2011, 11:19 
Не в сети

Зарегистрирован: 15 авг 2009, 21:04
Сообщения: 41
Откуда: Казахстан
Карма: 10
Итак данный скрипт соединяется с оборудованием на RouterOS по сетевому протоколу TCP к порту 8728. Далее через это соединение он отправляет запросы и получает ответы.
Для того чтобы это заработало в самом маршрутизаторе нужно открыть службу API.
Код:
 [sysadmin@CORE] > ip service enable api

Ну и разумеется предусмотреть свободный проход пакетов через фаерволы, если такие имеются. Команды отправляются по одной в виде набора строк, заканчивающейся нулевым символом. Сам протокол связи достаточно сложен, однако используя данную библиотеку все упрощается, и команды представляются в виде простого набора строк.
В частности:
Код:
/ip/address/add
=interface=ether1
=address=10.0.0.1/24

Команды для работы с микротиком частично дублируют свои аналоги из коммандной оболочки, частично являются оригинальными.
Подробней об этом можно почитать по ссылке:
http://wiki.mikrotik.com/wiki/Manual:API

_________________
Arbeit macht frei


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Mikrotik API Client
СообщениеДобавлено: 14 апр 2011, 11:34 
Не в сети

Зарегистрирован: 15 авг 2009, 21:04
Сообщения: 41
Откуда: Казахстан
Карма: 10
Если убрать лишнюю шелуху то алгоритм работы с библиотекой будет выглядеть так:
Код:
ApiAnswer answer = new ApiAnswer();
ApiCommand command = new ApiCommand();
ApiConn conn = new ApiConn(host, port);
String str;

conn.run(); //Подключаемся к микротику
if (!conn.isConnected()) {
print("Cannot connect!");
exit;
}
command.add("/ip/address/add"); //Задаем какую-нибудь команду
command.add("=interface=ether1");
command.add("=address=10.0.0.1/24");
conn.sendCommand(command.getText());//Отправляем ее микротику
str = conn.getData();
answer.change(str);
if (answer.isError()) print("Error " + str);
else print("OK");
command.clear(); //готовимся к отправке слудующей команды.


В случае если команда выводит список, то принимать данные придется в цикле до тех пор пока в строках, выдаваемых conn.getData() не встретится "done!".

_________________
Arbeit macht frei


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Mikrotik API Client
СообщениеДобавлено: 21 июн 2012, 15:21 
Не в сети
Разработчик

Зарегистрирован: 08 ноя 2007, 01:05
Сообщения: 8343
Откуда: Уфа
Карма: 238
Добавил в 5.2 обертку для Mikrotik Api. MikrotikApiSession.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Mikrotik API Client
СообщениеДобавлено: 21 июн 2012, 15:45 
Не в сети
Разработчик

Зарегистрирован: 08 ноя 2007, 01:05
Сообщения: 8343
Откуда: Уфа
Карма: 238
А команды в шлюзе можно писать по старому , а в скрипте шлюза сделать преобразование (разбить на строки, начинающиеся с "=", заменить пробелы на "/" ).


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Mikrotik API Client
СообщениеДобавлено: 25 янв 2013, 18:12 
Не в сети
Аватара пользователя

Зарегистрирован: 23 мар 2009, 23:16
Сообщения: 780
Откуда: St.Petersburg
Карма: 0
Всем доброго дня.
Может кто подсобит добавить сюда таймаут? Через какое-то время подозреваю подвисание задачи открытия шлюза и начинают копиться задачи, из-за чего вскоре перестает работать шедалер.
Хотелось бы, чтобы в случае проблем с коннектом или получением ответов от шлюза, скрипт не подвисал, а завершался по таймауту.

Таймаут на коннект вроде есть:

Код:
  public void run() {
    try {
      InetAddress ia = InetAddress.getByName(ipAddress);
      if (ia.isReachable(1000)) {
        sock = new Socket(ipAddress, ipPort);
        in = new DataInputStream(sock.getInputStream());
        out = new DataOutputStream(sock.getOutputStream());
        connected = true;
        readCommand = new ReadCommand(in, queue);
        writeCommand = new WriteCommand(out);
        this.listen();
        message = "Connected";


Но я подозреваю, что коннект проходит, а вот ответов от нее не доходит... ((

Буду очень благодарен за помощь!

PS: Версия биллинга 5.1


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Mikrotik API Client
СообщениеДобавлено: 25 янв 2013, 21:33 
Не в сети
Аватара пользователя

Зарегистрирован: 23 мар 2009, 23:16
Сообщения: 780
Откуда: St.Petersburg
Карма: 0
Висит уже десяток минут. В логах шедалера движение прекратилось, но в планировщике вижу одну запущенную задачу...

Вывод статуса шедалера

Код:
#./scheduler_status.sh
Sending 'status' on 127.0.0.1:9066
Result: TaskExecuter working
Started: 25.01.2013 18:29:38    Uptime: 0 d 01:00:52
Memory total: 411 041 792; max: 1 035 993 088; free: 273 795 200
Memory pools:
Non-heap memory[Code Cache]: max: 50 331 648; used: 6 376 256; peek: 6 509 504
Heap memory[PS Eden Space]: max: 39 845 888; used: 27 216 856; peek: 119 275 520
Heap memory[PS Survivor Space]: max: 39 845 888; used: 544 168; peek: 39 845 888
Heap memory[PS Old Gen]: max: 956 301 312; used: 109 485 568; peek: 363 924 472
Non-heap memory[PS Perm Gen]: max: 67 108 864; used: 17 976 048; peek: 17 976 048
Thread count: 128
Trees in cache: 92
Periodic tasks executed: 64; active: 1
Urgent tasks executed: 1; active: 0
Connections pool to Master status Idle: 20; Active: 3; maxActive: 300; maxIdle: 20


Не пойму что происходит и как отловить проблему, суть которой - накопление запущенных периодических задачь...


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Mikrotik API Client
СообщениеДобавлено: 28 янв 2013, 17:03 
Не в сети
Разработчик

Зарегистрирован: 08 ноя 2007, 01:05
Сообщения: 8343
Откуда: Уфа
Карма: 238
mikos писал(а):
Всем доброго дня.
Может кто подсобит добавить сюда таймаут? Через какое-то время подозреваю подвисание задачи открытия шлюза и начинают копиться задачи, из-за чего вскоре перестает работать шедалер.
Хотелось бы, чтобы в случае проблем с коннектом или получением ответов от шлюза, скрипт не подвисал, а завершался по таймауту.

Таймаут на коннект вроде есть:

Код:
  public void run() {
    try {
      InetAddress ia = InetAddress.getByName(ipAddress);
      if (ia.isReachable(1000)) {
        sock = new Socket(ipAddress, ipPort);
        in = new DataInputStream(sock.getInputStream());
        out = new DataOutputStream(sock.getOutputStream());
        connected = true;
        readCommand = new ReadCommand(in, queue);
        writeCommand = new WriteCommand(out);
        this.listen();
        message = "Connected";


Но я подозреваю, что коннект проходит, а вот ответов от нее не доходит... ((

Буду очень благодарен за помощь!

PS: Версия биллинга 5.1


Код:
sock.setSoTimeout( xxxx);


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Mikrotik API Client
СообщениеДобавлено: 22 авг 2013, 15:52 
Не в сети
Клиент
Аватара пользователя

Зарегистрирован: 03 авг 2009, 18:42
Сообщения: 7166
Откуда: Благовещенск
Карма: 241
stark писал(а):
Добавил в 5.2 обертку для Mikrotik Api. MikrotikApiSession.

ненашел как в доке пользоваться, можно поподробней

_________________
Код:
  Клиент: вер. 6.2.714 / 25.05.2015 17:27:15
    os: Linux; java: Java HotSpot(TM) 64-Bit Server VM, v.1.8.0_45
  Сервер: вер. 6.2.881 / 22.05.2015 17:56:55
    os: Linux; java: Java HotSpot(TM) 64-Bit Server VM, v.1.8.0_45
Помощь по администрированию bgbilling в jabber конференции или Группа в telegram
Стиль программирования - пьяный мастерстер
Разработка мобильных приложений


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Mikrotik API Client
СообщениеДобавлено: 22 авг 2013, 16:59 
Не в сети
Разработчик

Зарегистрирован: 08 ноя 2007, 01:05
Сообщения: 8343
Откуда: Уфа
Карма: 238
skyb писал(а):
stark писал(а):
Добавил в 5.2 обертку для Mikrotik Api. MikrotikApiSession.

ненашел как в доке пользоваться, можно поподробней


Для inet есть такой пример .
http://wiki.bgbilling.ru/index.php/%D0% ... krotik_api)

И класс MikrotikServiceActivator в диначическом коде. В нем
Код:
@Override
   protected void executeCommand( String command )
       throws Exception
   {
      logger.info( "execute: " + command );   
      command = command.replace( "\\n", "\n" );      
      String result = session.doCommand( command );
      logger.info( "result=" + result );
   }


По аналогии можно и для IPN сделать.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Mikrotik API Client
СообщениеДобавлено: 22 авг 2013, 17:59 
Не в сети
Клиент
Аватара пользователя

Зарегистрирован: 03 авг 2009, 18:42
Сообщения: 7166
Откуда: Благовещенск
Карма: 241
я так понял для ipn уже сделано, интересует ipn

_________________
Код:
  Клиент: вер. 6.2.714 / 25.05.2015 17:27:15
    os: Linux; java: Java HotSpot(TM) 64-Bit Server VM, v.1.8.0_45
  Сервер: вер. 6.2.881 / 22.05.2015 17:56:55
    os: Linux; java: Java HotSpot(TM) 64-Bit Server VM, v.1.8.0_45
Помощь по администрированию bgbilling в jabber конференции или Группа в telegram
Стиль программирования - пьяный мастерстер
Разработка мобильных приложений


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Mikrotik API Client
СообщениеДобавлено: 22 авг 2013, 18:23 
Не в сети
Разработчик

Зарегистрирован: 08 ноя 2007, 01:05
Сообщения: 8343
Откуда: Уфа
Карма: 238
skyb писал(а):
я так понял для ipn уже сделано, интересует ipn

цикл однако бесконечный :)


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Mikrotik API Client
СообщениеДобавлено: 22 авг 2013, 19:08 
Не в сети
Клиент
Аватара пользователя

Зарегистрирован: 03 авг 2009, 18:42
Сообщения: 7166
Откуда: Благовещенск
Карма: 241
stark писал(а):
skyb писал(а):
я так понял для ipn уже сделано, интересует ipn

цикл однако бесконечный :)

да не, мне интересно как использовать в ipn этот api если он реализован_)

_________________
Код:
  Клиент: вер. 6.2.714 / 25.05.2015 17:27:15
    os: Linux; java: Java HotSpot(TM) 64-Bit Server VM, v.1.8.0_45
  Сервер: вер. 6.2.881 / 22.05.2015 17:56:55
    os: Linux; java: Java HotSpot(TM) 64-Bit Server VM, v.1.8.0_45
Помощь по администрированию bgbilling в jabber конференции или Группа в telegram
Стиль программирования - пьяный мастерстер
Разработка мобильных приложений


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 21 ] 

Часовой пояс: UTC + 5 часов [ Летнее время ]


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  
cron
POWERED_BY
Русская поддержка phpBB
[ Time : 0.125s | 62 Queries | GZIP : On ]