One place for hosting & domains

      primeros

      SOLID: Los primeros 5 principios del diseño orientado a objetos


      Introducción

      SOLID es un acrónimo de los primeros cinco principios del diseño orientado a objetos (OOD) de Robert C. Martin (también conocido como el Tío Bob).

      Nota: Aunque estos principios pueden aplicarse a varios lenguajes de programación, el código de muestra que se incluye en este artículo usará PHP.

      Estos principios establecen prácticas que se prestan al desarrollo de software con consideraciones para su mantenimiento y expansión a medida que el proyecto se amplía. Adoptar estas prácticas también puede ayudar a evitar los aromas de código, refactorizar el código y aprender sobre el desarrollo ágil y adaptativo de software.

      SOLID representa:

      En este artículo, se le presentará cada principio por separado para comprender la forma en que SOLID puede ayudarlo a ser un mejor desarrollador.

      Principio de responsabilidad única

      El principio de responsabilidad única (SRP) establece:

      Una clase debe tener una y una sola razón para cambiar, lo que significa que una clase debe tener solo un trabajo.

      Por ejemplo, considere una aplicación que toma una colección de formas, entre círculos y cuadrados, y calcula la suma del área de todas las formas de la colección.

      Primero, cree las clases de forma y haga que los constructores configuren los parámetros requeridos.

      Para las cuadrados, deberá saber la longitud de un lado:

      class Square
      {
          public $length;
      
          public function construct($length)
          {
              $this->length = $length;
          }
      }
      

      Para los círculos, deberá saber el radio:

      class Circle
      {
          public $radius;
      
          public function construct($radius)
          {
              $this->radius = $radius;
          }
      }
      

      A continuación, cree la clase AreaCalculator y luego escriba la lógica para sumar las áreas de todas las formas proporcionadas. El área de un cuadrado se calcula por longitud al cuadrado. El área de un círculo se calcula mediante pi por el radio al cuadrado.

      class AreaCalculator
      {
          protected $shapes;
      
          public function __construct($shapes = [])
          {
              $this->shapes = $shapes;
          }
      
          public function sum()
          {
              foreach ($this->shapes as $shape) {
                  if (is_a($shape, 'Square')) {
                      $area[] = pow($shape->length, 2);
                  } elseif (is_a($shape, 'Circle')) {
                      $area[] = pi() * pow($shape->radius, 2);
                  }
              }
      
              return array_sum($area);
          }
      
          public function output()
          {
              return implode('', [
                '',
                    'Sum of the areas of provided shapes: ',
                    $this->sum(),
                '',
            ]);
          }
      }
      

      Para usar la clase AreaCalculator, deberá crear una instancia de la clase y pasar una matriz de formas para mostrar el resultado en la parte inferior de la página.

      A continuación, se muestra un ejemplo con una colección de tres formas:

      • un círculo con un radio de 2
      • un cuadrado con una longitud de 5
      • un segundo cuadrado con una longitud de 6
      $shapes = [
        new Circle(2),
        new Square(5),
        new Square(6),
      ];
      
      $areas = new AreaCalculator($shapes);
      
      echo $areas->output();
      

      El problema con el método de salida es que AreaCalculator maneja la lógica para generar los datos.

      Considere un escenario en el que el resultado debe convertirse a otro formato como JSON.

      La clase AreaCalculator manejaría toda la lógica. Esto violaría el principio de responsabilidad única. La clase AreaCalculator solo debe ocuparse de la suma de las áreas de las formas proporcionadas. No debería importar si el usuario desea JSON o HTML.

      Para abordar esto, puede crear una clase SumCalculatorOutputter por separado y usarla para manejar la lógica que necesita para mostrar los datos al usuario:

      class SumCalculatorOutputter
      {
          protected $calculator;
      
          public function __constructor(AreaCalculator $calculator)
          {
              $this->calculator = $calculator;
          }
      
          public function JSON()
          {
              $data = [
                'sum' => $this->calculator->sum(),
            ];
      
              return json_encode($data);
          }
      
          public function HTML()
          {
              return implode('', [
                '',
                    'Sum of the areas of provided shapes: ',
                    $this->calculator->sum(),
                '',
            ]);
          }
      }
      

      La clase SumCalculatorOutputter funcionaría así:

      $shapes = [
        new Circle(2),
        new Square(5),
        new Square(6),
      ];
      
      $areas = new AreaCalculator($shapes);
      $output = new SumCalculatorOutputter($areas);
      
      echo $output->JSON();
      echo $output->HTML();
      

      Ahora, la clase SumCalculatorOutputter maneja cualquier lógica que necesite para enviar los datos al usuario.

      Eso cumple con el principio de responsabilidad única.

      Principio abierto-cerrado

      Principio abierto-cerrado (S.R.P.) establece:

      Los objetos o entidades deben estar abiertos por extensión, pero cerrados por modificación.

      Esto significa que una clase debe ser ampliable sin modificar la clase en sí.

      Volvamos a ver la clase AreaCalculator y enfoquémonos en el método sum:

      class AreaCalculator
      {
          protected $shapes;
      
          public function __construct($shapes = [])
          {
              $this->shapes = $shapes;
          }
      
          public function sum()
          {
              foreach ($this->shapes as $shape) {
                  if (is_a($shape, 'Square')) {
                      $area[] = pow($shape->length, 2);
                  } elseif (is_a($shape, 'Circle')) {
                      $area[] = pi() * pow($shape->radius, 2);
                  }
              }
      
              return array_sum($area);
          }
      }
      

      Considere un escenario en el que el usuario desea la sum de formas adicionales como triángulos, pentágonos, hexágonos, etc. Tendría que editar constantemente este archivo y añadir más bloques if/else. Eso violaría el principio abierto-cerrado.

      Una forma de mejorar el método sum es eliminar la lógica para calcular el área de cada forma fuera del método de la clase AreaCalculator y adjuntarlo a la clase de cada forma.

      A continuación, se muestra area definido en Square:

      class Square
      {
          public $length;
      
          public function __construct($length)
          {
              $this->length = $length;
          }
      
          public function area()
          {
              return pow($this->length, 2);
          }
      }
      

      Y aquí es el método area definido en Circle:

      class Circle
      {
          public $radius;
      
          public function construct($radius)
          {
              $this->radius = $radius;
          }
      
          public function area()
          {
              return pi() * pow($shape->radius, 2);
          }
      }
      

      El método sum para AreaCalculator puede reescribirse así:

      class AreaCalculator
      {
          // ...
      
          public function sum()
          {
              foreach ($this->shapes as $shape) {
                  $area[] = $shape->area();
              }
      
              return array_sum($area);
          }
      }
      

      Ahora, puede crear otra clase de forma y pasarla al calcular la suma sin romper el código.

      Sin embargo, ahora surge otro problema: ¿Cómo sabe que el objeto pasado a AreaCalculator es realmente una forma o si la forma tiene un método llamado area?

      La codificación de una interface es una parte integral de SOLID.

      Cree un ShapeInterface que sea compatible con area:

      interface ShapeInterface
      {
          public function area();
      }
      

      Modifique sus clases de forma para implement el ShapeInterface.

      A continuación, se muestra la actualización a Square:

      class Square implements ShapeInterface
      {
          // ...
      }
      

      Y aquí está la actualización a Circle:

      class Circle implements ShapeInterface
      {
          // ...
      }
      

      En el método sum para AreaCalculator, puede verificar si las formas proporcionadas son realmente instancias de ShapeInterface; de lo contrario, lanzamos una excepción:

       class AreaCalculator
      {
          // ...
      
          public function sum()
          {
              foreach ($this->shapes as $shape) {
                  if (is_a($shape, 'ShapeInterface')) {
                      $area[] = $shape->area();
                      continue;
                  }
      
                  throw new AreaCalculatorInvalidShapeException();
              }
      
              return array_sum($area);
          }
      }
      

      Eso cumple con el principio abierto-cerrado.

      Principio de sustitución de Liskov

      El principio de sustitución de Liskov establece:

      Digamos que q(x) sea una propiedad demostrable sobre objetos de x, de tipo T. Entonces, q(y) debe ser demostrable para los objetos y, de tipo S, donde S es un subtipo de T.

      Esto significa que cada subclase o clase derivada debe ser sustituible por su clase base o clase principal.

      A partir de la clase AreaCalculator mostrada como ejemplo, considere una nueva clase VolumeCalculator que extiende la clase AreaCalculator:

      class VolumeCalculator extends AreaCalculator
      {
          public function construct($shapes = [])
          {
              parent::construct($shapes);
          }
      
          public function sum()
          {
              // logic to calculate the volumes and then return an array of output
              return [$summedData];
          }
      }
      

      Recuerde que la clase SumCalculatorOutputter se asemeja a esto:

      class SumCalculatorOutputter {
          protected $calculator;
      
          public function __constructor(AreaCalculator $calculator) {
              $this->calculator = $calculator;
          }
      
          public function JSON() {
              $data = array(
                  'sum' => $this->calculator->sum();
              );
      
              return json_encode($data);
          }
      
          public function HTML() {
              return implode('', array(
                  '',
                      'Sum of the areas of provided shapes: ',
                      $this->calculator->sum(),
                  ''
              ));
          }
      }
      

      Si intenta ejecutar un ejemplo como este:

      $areas = new AreaCalculator($shapes);
      $volumes = new VolumeCalculator($solidShapes);
      
      $output = new SumCalculatorOutputter($areas);
      $output2 = new SumCalculatorOutputter($volumes);
      

      Cuando invoca el método HTML en el objeto $output2, obtendrá un error E_NOTICE que le informará de conversión de matriz a cadena.

      Para solucionar esto, en vez de devolver una matriz desde el método sum de la clase VolumeCalculator, devuelva $summedData:

      class VolumeCalculator extends AreaCalculator
      {
          public function construct($shapes = [])
          {
              parent::construct($shapes);
          }
      
          public function sum()
          {
              // logic to calculate the volumes and then return a value of output
              return $summedData;
          }
      }
      

      $summedData puede ser float, double o integer.

      Eso cumple con el principio de sustitución de Liskov.

      Principio de segregación de interfaz

      El principio de segregación de interfaz establece:

      Un cliente nunca debe ser forzado a implementar una interfaz que no usan ni los clientes no deben ser forzados a depender de métodos que no usan.

      Siguiendo con el ejemplo anterior de ShapeInterface, tendrá que admitir las nuevas formas tridimensionales de Cuboid y Spheroid, y estas formas también tendrán que calcular el volumen.

      Consideraremos lo que sucedería si modificara ShapeInterface para añadir otro contrato:

      interface ShapeInterface
      {
          public function area();
      
          public function volume();
      }
      

      Ahora, cualquier forma que cree debe implementar el método volume, pero sabemos que las cuadrados son formas planas y que no tienen volumen, por lo que esta interfaz forzaría a la clase Square a implementar un método que no usa.

      Esto violaría el principio de segregación de interfaz. En su lugar, podría crear otra interfaz llamada ThreeDimensionalShapeInterface que tiene el contrato de volume y las formas tridimensionales pueden implementar esta interfaz:

      interface ShapeInterface
      {
          public function area();
      }
      
      interface ThreeDimensionalShapeInterface
      {
          public function volume();
      }
      
      class Cuboid implements ShapeInterface, ThreeDimensionalShapeInterface
      {
          public function area()
          {
              // calculate the surface area of the cuboid
          }
      
          public function volume()
          {
              // calculate the volume of the cuboid
          }
      }
      

      Este es un enfoque mucho mejor, pero hay que tener cuidado cuando se trata de escribir estas interfaces En vez de usar un ShapeInterface o un ThreeDimensionalShapeInterface, puede crear otra interfaz, quizá ManageShapeInterface e implementarla en las formas planas y en las tridimensionales.

      De esta manera, puede tener una sola API para administrar las formas:

      interface ManageShapeInterface
      {
          public function calculate();
      }
      
      class Square implements ShapeInterface, ManageShapeInterface
      {
          public function area()
          {
              // calculate the area of the square
          }
      
          public function calculate()
          {
              return $this->area();
          }
      }
      
      class Cuboid implements ShapeInterface, ThreeDimensionalShapeInterface, ManageShapeInterface
      {
          public function area()
          {
              // calculate the surface area of the cuboid
          }
      
          public function volume()
          {
              // calculate the volume of the cuboid
          }
      
          public function calculate()
          {
              return $this->area();
          }
      }
      

      Ahora en la clase AreaCalculator, puede sustituir la invocación al método area con calculate y también verificar si el objeto es una instancia de ManageShapeInterface y no de ShapeInterface.

      Eso cumple con el principio de segregación de interfaz.

      Principio de inversión de dependencia

      El principio de inversión de dependencia establece:

      Las entidades deben depender de abstracciones, no de concreciones. Indica que el módulo de alto nivel no debe depender del módulo de bajo nivel, sino que deben depender de las abstracciones.

      Este principio permite el desacoplamiento.

      A continuación, se muestra un ejemplo de un PasswordReminder que se conecta a una base de datos de MySQL:

      class MySQLConnection
      {
          public function connect()
          {
              // handle the database connection
              return 'Database connection';
          }
      }
      
      class PasswordReminder
      {
          private $dbConnection;
      
          public function __construct(MySQLConnection $dbConnection)
          {
              $this->dbConnection = $dbConnection;
          }
      }
      

      Primero, MySQLConnection es el módulo de bajo nivel mientras que PasswordReminder es de alto nivel, pero según la definición de D en SOLID, que establece que Depende de la abstracción y no de las concreciones. Este fragmento de código anterior viola este principio, ya que se está forzando a la clasevPasswordReminder a depender de la clase MySQLConnection.

      Si más adelante cambiara el motor de la base de datos, también tendría que editar la clase PasswordReminder, y esto violaría el principio abierto-cerrado.

      A la clase PasswordReminder no le debe importar qué base de datos usa su aplicación. Para solucionar estos problemas, se puede codificar a una interfaz, ya que los módulos de alto nivel y bajo nivel deben depender de la abstracción:

      interface DBConnectionInterface
      {
          public function connect();
      }
      

      La interfaz tiene un método connect y la clase MySQLConnection implementa esta interfaz. Además, en lugar de escribir directamente la clase MySQLConnection en el constructor del PasswordReminder, se indica la clase DBConnectionInterface y, sin importar el tipo de base de datos que utilice su aplicación, la clase PasswordReminder puede conectarse sin ningún problema a la base de datos y no se viola el principio abierto-cerrado.

      class MySQLConnection implements DBConnectionInterface
      {
          public function connect()
          {
              // handle the database connection
              return 'Database connection';
          }
      }
      
      class PasswordReminder
      {
          private $dbConnection;
      
          public function __construct(DBConnectionInterface $dbConnection)
          {
              $this->dbConnection = $dbConnection;
          }
      }
      

      Este código establece que los módulos de alto nivel y los de bajo nivel dependen de la abstracción.

      Conclusión

      En este artículo, se le presentaron los cinco principios del código SOLID. Los proyectos que se adhieren a los principios SOLID pueden compartirse con los colaboradores, ampliarse, modificarse, probarse y refactorizarse con menos complicaciones.

      Continúe aprendiendo leyendo sobre otras prácticas para el desarrollo ágil y adaptativo de software.



      Source link

      Dar los primeros pasos con redes definidas por software y crear una VPN con ZeroTier One


      Introducción

      Actualmente, cada vez se crean más proyectos de software a través de equipos cuyos miembros trabajan juntos desde ubicaciones geográficas apartadas. Aunque este flujo de trabajo ofrece muchas ventajas claras, existen casos en los cuales los equipos pueden desear vincular sus computadoras a través de Internet y tratarlas como si estuviesen en la misma habitación. Por ejemplo, es posible que pruebe sistemas distribuidos como Kubernetes o compilando una aplicación multiservicio compleja. A veces, contribuye a la productividad la posibilidad de tratar las máquinas como si estuviesen juntas, ya que no se debe correr el riesgo de exponer servicios inacabados a Internet. Este paradigma se puede lograr mediante la redes definidas por software (SDN), una tecnología relativamente nueva que proporciona una trama de red dinámica completamente integrada por software.

      ZeroTier One es una aplicación de código abierto que utiliza algunos de los últimos desarrollos en materia de SDN para permitir a los usuarios crear redes seguras y manejables, y tratar los dispositivos conectados como si estuviesen en la misma ubicación física. ZeroTier proporciona una consola web para software de administración de redes y de extremos para los clientes. Es una tecnología punto a punto cifrada, lo cual significa que a diferencia de lo que sucede con las soluciones de VPN tradicionales, las comunicaciones no tienen que pasar a través de un servidor o enrutador central; los mensajes se envían directamente de host a host. En consecuencia, es muy eficiente y garantiza una latencia mínima. Entre otros beneficios, se incluyen el proceso de implementación y configuración sencillo de ZeroTier, su fácil mantenimiento y el hecho de que permite registrar y administrar de forma centraliza los nodos autorizados a través de la consola web.

      Siguiendo este tutorial, conectará un cliente y un servidor juntos en una red punto a punto simple. Debido a que la red definida por software no utiliza el diseño tradicional de cliente y servidor, no se debe instalar ni configurar un servidor VPN central; esto agiliza la implementación de la herramienta y la adición de nodos complementarios. Una vez establecida la conectividad, tendrá la oportunidad de utilizar la capacidad VPN de ZeroTier empleando algunas funcionalidades inteligentes de Linux para permitir que el tráfico salga de su red ZerTier desde su servidor e indicar a un cliente que envíe su tráfico en esa dirección.

      Requisitos previos

      Antes de realizar este tutorial, necesitará los siguientes recursos:

      • Un servidor con Ubuntu 16.04. En este servidor, también necesitará un usuario no root con privilegios sudo que se pueda configurar usando nuestra guía de configuración inicial para servidores de Ubuntu 16.04.

      • Una cuenta con ZeroTier One, que puede configurar visitando MyZeroTier. Para realizar este tutorial, puede usar la versión gratuita de este servicio, sin costo ni compromisos.

      • Una computadora local para que se una a su SDN como cliente. En los ejemplos de este tutorial, tanto el servidor como el equipo local cuentan con Ubuntu Linux, pero cualquier sistema operativo listado en la página de descarga de ZeroTier funcionará en el cliente.

      Una vez cumplidos esos requisitos previos, estará listo para configurar redes definidas por software para su servidor y su equipo local.

      Paso 1: Crear una red definida por software usando ZeroTier One

      La plataforma ZeroTier proporciona el punto central de control para su red definida por software. En ella, podrá autorizar y desautorizar clientes, elegir un esquema de dirección y crear un ID de red al cual puede dirigir a sus clientes cuando los configure.

      Inicie sesión en su cuenta de ZerTier, haga clic en Networks en la parte superior de la pantalla y luego seleccione Create. Aparecerá un nombre de red generado automáticamente. Haga clic para ver la pantalla de configuración de su red. Tome nota del parámetro Network ID que aparece en amarillo, ya que necesitará consultarlo más tarde.

      Si prefiere cambiar el nombre de la red por algo más descriptivo, edite el nombre en el lado izquierdo de la pantalla; también puede añadir una descripción, si lo desea. Cualquier cambio que realice se guardará y se aplicará automáticamente.

      A continuación, seleccione el rango de dirección IPv4 en el que funcionará la SDN. En el lado derecho de la pantalla, en el área titulada IPv4 Auto-Assign, seleccione un rango de direcciones al que pertenecerán sus nodos. A los efectos de este tutorial, puede utilizarse cualquier rango, pero es importante dejar seleccionada la casilla Auto-Assign from Range.

      Asegúrese de que quede marcado el parámetro Certificate (Private Network) en Access Control, a la izquierda. Esto garantiza que solo las computadoras aprobadas puedan conectarse a su red, y que no lo haga cualquiera que conozca el ID de esta.

      Una vez que termine, sus ajustes deben tener un aspecto similar a este:

      Configurar ZeroTier

      En este punto, habrá creado con éxito los elementos básicos de una red definida por software de ZeroTier. A continuación, instalará el software de ZeroTier en su servidor y en más máquinas clientes para permitirles establecer conexión con su SDN.

      Paso 2: Instalar el cliente de ZeroTier One en su servidor y su máquina local

      Debido a que ZeroTier One es un software relativamente nuevo, aún no se ha incluido en los repositorios de software centrales de Ubuntu. Por este motivo, ZeroTier ofrece una secuencia de comandos de instalación que usaremos para instalar el software. Este comando es una secuencia de comandos con firma GPG, lo cual significa que el código que descargue se verificará como publicado por ZeroTier. Esta secuencia de comandos tiene cuatro partes principales. A continuación, se muestra una explicación de cada una de ellas:

      • curl -s 'https://pgp.mit.edu/pks/lookup?op=get&search=0x1657198823E52A61': esto importa la clave pública de ZeroTier de MIT.
      • gpg --import: esta sección del comando añade la clave pública de ZeroTier a su cadena de claves local de autoridades de confianza para los paquetes que intente instalar. La siguiente parte del comando solo se ejecutará si la importación de GPG se completa de forma correcta.
      • if z=$(curl -s 'https://install.zerotier.com/' | gpg); then echo "$z": en esta sección tienen lugar varios eventos. No obstante, el concepto es básicamente el siguiente: “Si GPG admite la secuencia de comandos de instalación con firma criptográfica descargada de ZeroTier.com y esta no se rechaza por no estar, en apariencia, firmada por ZeroTier, se debe pegar esa información en la pantalla”.
      • sudo bash; fi: esta sección toma la secuencia de comandos del instalador recién validado y lo ejecuta realmente antes de finalizar la rutina.

      Advertencia: Nunca debe descargar algo de Internet y asignarlo a otro programa a menos que esté seguro de que proviene de una fuente confiable. Si lo desea, puede inspeccionar el software de ZeroTier revisando el código fuente en la página oficial de GitHub del proyecto.

      Utilice una consola SSH para establecer conexión con su servidor recién creado y ejecute el siguiente comando como usuario normal (a continuación, verá una explicación del comando). Asegúrese de no ejecutarlo como root, ya que la secuencia de comandos solicita automáticamente su contraseña para elevar su nivel de privilegios, y recuerde mantener la consola de ZeroTier abierta en su navegador para poder interactuar con ella cuando sea necesario.

      • curl -s 'https://pgp.mit.edu/pks/lookup?op=get&search=0x1657198823E52A61' | gpg --import && if z=$(curl -s 'https://install.zerotier.com/' | gpg); then echo "$z" | sudo bash; fi

      Una vez que la secuencia de comandos se complete, verá dos líneas de resultado similares a las que se muestran a continuación. Tome nota de su dirección de ZeroTier (sin los corchetes) y del nombre del sistema que generó esa dirección; los necesitará más tarde.

      Output

      *** Waiting for identity generation... *** Success! You are ZeroTier address [ 916af8664d ].

      Repita este paso en su computadora local si utiliza Ubuntu, o siga los pasos pertinentes para su sistema operativo en la página de descargas del sitio web de ZeroTier. Una vez más, asegúrese de anotar la dirección de ZeroTier y la máquina que generó dicha dirección. Necesitará esta información en el siguiente paso de este tutorial cuando una su servidor y cliente a la red.

      Paso 3: Unirse a su red ZeroTier

      Ahora que tanto el servidor como el cliente tienen activo el software de ZeroTier, estará listo para conectarlos a la red que creó en la consola web de ZeroTier.

      Utilice el siguiente comando para indicar a su cliente que solicite acceso a la red ZeroTier a través de su plataforma. La solicitud inicial del cliente se rechazará y quedará pendiente, pero solucionaremos eso en un momento. Asegúrese de sustituir NetworkID por el ID de red que indicó anteriormente desde la ventana de configuración de su red.

      • sudo zerotier-cli join NetworkID

      Output

      200 join OK

      Recibirá un mensaje 200 join OK, lo cual confirmará que el servicio ZeroTier de su servidor pudo interpretar el comando. Si no lo hace, compruebe el ID de red de ZeroTier que introdujo.

      Debido a que no creó una red pública a la que pueda unirse cualquier persona en el mundo, deberá autorizar sus clientes. Vaya a la consola web de ZeroTier y desplácese hasta la parte inferior donde se encuentra la sección de miembros. Debería ver dos entradas marcadas como Online, con las mismas direcciones indicadas anteriormente.

      En la primera columna marcada como Auth?, seleccione las casillas para autorizarlas a unirse a la red. El controlador de ZeroTier asignará una dirección IP al servidor y el cliente del rango que seleccionó la próxima vez que invoquen a la SDN.

      Asignar las direcciones IP tomará un momento. Mientras espera, podría proporcionar un nombre corto y una descripción para sus nodos en la sección de miembros.

      De esta menra, habrá conectado dos sistemas a su red definida por software.

      Hasta ahora, se familiarizó con el panel de control de ZeroTier, usó la interfaz de la línea de comandos para descargar e instalar ZeroTier y luego conectó el servidor y el cliente a esa red. A continuación, comprobará que todo se haya aplicado correctamente realizando una prueba de conectividad.

      Paso 4: Verificar la conectividad

      En esta etapa, es importante validar que los dos hosts puedan comunicarse. Existe la posibilidad de que aún cuando parezca que los host se unieron a la red no puedan comunicarse. Al verificar la conectividad, no tendrá que preocuparse por problemas básicos de interconexión que podrían causar problemas posteriormente.

      Una alternativa sencilla para encontrar la dirección IP de ZeroTier de cada host es buscar en la sección de miembros de la consola web de ZeroTier. Es posible que necesite actualizarla tras autorizar al servidor y al cliente antes de que aparezcan sus direcciones IP. También puede usar la línea de comandos de Linux para buscar estas direcciones. Utilice el siguiente comando en ambos equipos; la primera dirección IP de la lista es la que debe usar. En el ejemplo que se muestra a continuación, esa dirección es 203.0.113.0.

      • ip addr sh zt0 | grep 'inet'

      Output

      inet 203.0.113.0/24 brd 203.0.255.255 scope global zt0 inet6 fc63:b4a9:3507:6649:9d52::1/40 scope global inet6 fe80::28e4:7eff:fe38:8318/64 scope link

      Para probar la conectividad entre los hosts, ejecute el comando ping desde un host seguido de la dirección del otro. Por ejemplo, en el cliente:

      Y en el servidor:

      Si el host opuesto muestra una respuesta (como se muestra en el resultado, a continuación), significa que los dos nodos se comunican correctamente a través de la SDN.

      Output

      PING 203.0.113.0 (203.0.113.0) 56(84) bytes of data. 64 bytes from 203.0.113.0: icmp_seq=1 ttl=64 time=0.054 ms 64 bytes from 203.0.113.0: icmp_seq=2 ttl=64 time=0.046 ms 64 bytes from 203.0.113.0: icmp_seq=3 ttl=64 time=0.043 ms

      Puede añadir tantos equipos como lo desee a esta configuración repitiendo los procesos de instalación e incorporación para ZeroTier anteriormente descritos. Recuerde que no es necesario que estos equipos estén cerca uno de otro.

      Ahora que confirmó que su servidor y cliente pueden comunicarse entre sí, continúe leyendo para aprender a configurar la red de modo que proporcione una puerta de enlace de salida y construir su propia VPN.

      Paso 5: Habilitar la capacidad VPN de ZeroTier

      Como se mencionó en la introducción, es posible usar ZeroTier como herramienta de VPN. Si no planea usar ZeroTier como una solución de VPN, no necesita seguir este paso y puede ir directo al 6.

      El uso de una VPN oculta el origen de sus comunicaciones con sitios web en Internet. Le permite omitir filtros y restricciones que puedan existir en la red que usa. Para Internet en general, parecerá que navega desde la dirección IP pública de su servidor. Para usar ZeroTier como herramienta de VPN, deberá aplicar algunos cambios más a las configuraciones de su servidor y cliente.

      Habilitar la traducción de la dirección de red y el reenvío de IP

      La traducción de direcciones de red, más comúnmente conocida como “NAT”, es un método por el cual un enrutador acepta paquetes en una interfaz etiquetada con la dirección IP del remitente y luego cambia esa dirección por la del enrutador. Se conserva un registro de este cambio en la memoria del enrutador para que cuando el tráfico de retorno vuelva en la dirección opuesta, el enrutador pueda traducir el IP de vuelta para su dirección original. La NAT se utiliza normalmente para permitir que varias computadoras funcionen detrás de una dirección IP públicamente expuesta, lo cual es útil para un servicio de VPN. Un ejemplo de la NAT en la práctica es el enrutador doméstico que su proveedor de servicios de Internet le proporcionó para conectar todos los dispositivos de su hogar a Internet. Su portátil, su teléfono, sus tabletas y cualquier otro dispositivo habilitado para Internet aparecerán para compartir la misma dirección IP pública en Internet, porque su enrutador aplica NAT.

      Aunque el enrutador normalmente aplica NAT, un servidor también puede hacerlo. A lo largo de este paso, utilizará esta funcionalidad en su servidor ZeroTier para habilitar sus capacidades de VPN.

      El reenvío de IP es una función que realiza un router o un servidor. Mediante esta se reenvía el tráfico de una interfaz a otra si las direcciones IP están en zonas diferentes. Si un enrutador se conectó a dos redes, el reenvío de IP le permite reenviar el tráfico entre ellas. Esto puede parecer sencillo, pero su implementación correcta puede ser un proceso sorprendentemente complejo. Sin embargo, en el caso de este tutorial, bastará con editar algunos archivos de configuración.

      Si se habilita el reenvío de IP, el tráfico de la VPN desde su cliente en la red ZeroTier llegará a la interfaz de ZeroTier del servidor. Sin estos cambios en la configuración, el kernel de Linux (por defecto) desechará cualquier paquete no destinado a la interfaz a la que llegan. Este es un comportamiento normal para el kernel de Linux, ya que normalmente cualquier paquete que llegue a una interfaz que tenga una dirección de destino para otra red podría ser el resultado de una mala configuración del direccionamiento en cualquier otra parte de la red.

      Resulta útil concebir el reenvío de IP como un proceso mediante el cual se notifica al kernel de Linux que es aceptable reenviar paquetes entre las interfaces. El ajuste predeterminado es 0, que equivale a “inhabilitado”. Lo cambiará a 1, equivalente a “habilitado”.

      Para ver la configuración actual, ejecute el siguiente comando:

      • sudo sysctl net.ipv4.ip_forward

      Output

      net.ipv4.ip_forward = 0

      Para habilitar el reenvío de IP, modifique el archivo /etc/sysctl.conf en su servidor y añada la línea requerida. Este archivo de configuración permite que un administrador anule los ajustes predeterminados del kernel y siempre se aplicará después de los reinicios para que no tenga que preocuparse por configurarlos de nuevo. Utilice nano o su editor de texto favorito para añadir la siguiente línea a la parte inferior del archivo.

      • sudo nano /etc/sysctl.conf

      /etc/sysctl.conf

      . . .
      net.ipv4.ip_forward = 1
      

      Guarde y cierre el archivo, y luego ejecute el siguiente comando para activar la adopción del kernel de la nueva configuración

      El servidor adoptará cualquier directiva nueva de configuración en el archivo y la aplicará de inmediato, sin necesidad de un reinicio. Ejecute el mismo comando que aplicó antes; verá que el reenvío de IP está habilitado.

      • sudo sysctl net.ipv4.ip_forward

      Output

      net.ipv4.ip_forward = 1

      Ahora que el reenvío de IP está habilitado, podrá aprovecharlo al máximo proporcionando al servidor algunas reglas de direccionamiento básicas. Debido a que el kernel de Linux ya tiene una capacidad de direccionamiento de red integrada, lo único que debe hacer es añadir algunas reglas para indicar al firewall integrado y al enrutador que el nuevo tráfico que verá es aceptable y mostrarle el destino de este.

      Para añadir estas reglas desde la línea de comandos, primero necesitará saber los nombres que Ubuntu asignó a su interfaz de ZeroTier y a su interfaz ethernet regular para Internet. Normalmente, son zt0 y eth0 respectivamente, aunque no siempre es así.

      Para encontrar estos nombres de interfaces, utilice el comando ip link show. Esta utilidad de línea de comandos es parte de iproute2, un conjunto de utilidades del espacio de usuario que viene instalada en Ubuntu por defecto:

      En el resultado de este comando, los nombres de las interfaces se encuentran directamente junto a los números que identifican una interfaz única en la lista. Estos nombres de interfaces se resaltan en el siguiente resultado de ejemplo. Si el suyo difiere de los nombres que se muestran en el ejemplo, sustituya el nombre de su interfaz de forma correspondiente a lo largo de esta guía.

      Output

      1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000 link/ether 72:2d:7e:6f:5e:08 brd ff:ff:ff:ff:ff:ff 3: zt0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 2800 qdisc pfifo_fast state UNKNOWN mode DEFAULT group default qlen 1000 link/ether be:82:8f:f3:b4:cd brd ff:ff:ff:ff:ff:ff

      Con esa información, utilice iptables para habilitar la traducción de direcciones de red y el enmascaramiento de IP:

      • sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

      Permita el reenvío de tráfico y el seguimiento de las conexiones activas:

      • sudo iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

      A continuación, permita el reenvío de tráfico de zt0 a eth0. No es necesaria una regla inversa, ya que en este tutorial se supone que el cliente siempre realiza la invocación a través del servidor, y no al revés:

      • sudo iptables -A FORWARD -i zt0 -o eth0 -j ACCEPT

      Es importante recordar que las reglas de iptables que estableció para el servidor no persisten automáticamente entre los reinicios. Deberá guardar estas reglas para garantizar que se vuelvan a implementar si el servidor se reinicia. En su servidor, ejecute los comandos siguientes usando como guía las breves instrucciones en la pantalla para guardar las reglas IPv4 actuales; no se requiere IPv6.

      • sudo apt-get install iptables-persistent
      • sudo netfilter-persistent save

      Tras ejecutar sudo netfilter-persistent save, puede resultarle conveniente reiniciar su servidor para validar el almacenamiento correcto de las reglas de iptables. Una forma sencilla de verificar esto es ejecutar sudo iptables-save, que volcará la configuración actual cargada en la memoria a su terminal. Si ve reglas similares a las que se muestran a continuación en relación con el enmascaramiento, el reenvío y la interfaz zt0, significa que se guardaron correctamente.

      Output

      # Generated by iptables-save v1.6.0 on Tue Apr 17 21:43:08 2018 . . . -A POSTROUTING -o eth0 -j MASQUERADE COMMIT . . . -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -A FORWARD -i zt0 -o eth0 -j ACCEPT COMMIT . . .

      Ahora que estas reglas se aplicaron a su servidor, está listo para alternar el tráfico entre la red de ZeroTier y la Internet pública. Sin embargo, la VPN no funcionará a menos que la red ZeroTier esté informada de que el servidor está listo para utilizarse como una puerta de enlace.

      Habilitar su servidor para administrar la ruta global

      Para que su servidor procese el tráfico de cualquier cliente, debe asegurarse de que otros clientes de la red de ZeroTier puedan enviar su tráfico a él. Esto puede hacerse estableciendo una ruta global en la consola de ZeroTier. Aquellos que están familiarizados con las redes informáticas pueden describir esto como una Ruta predeterminada. Es donde cualquier cliente envía su tráfico predeterminado; es decir, cualquier tráfico que no debería ir a ninguna otra ubicación específica.

      Vaya a la parte superior derecha de su página de redes de ZeroTier y añada una nueva ruta con los parámetros siguientes. Puede encontrar el IP de ZeroTier para su servidor en la sección de miembros de su página de configuración de red de ZeroTier. En el campo network/bits, introduzca 0.0.0.0/0 y en el campo (LAN) la dirección IP de su servidor ZeroTier.

      Cuando se implementen los detalles, haga clic en el símbolo “+”; verá aparecer una nueva regla debajo de la existente. Un globo naranja en ella indicará que es de hecho una ruta global:

      Regla de ruta global

      Con su red de ZeroTier lista, solo queda configurar un aspecto para que la VPN funcione: los clientes.

      Configurar clientes de Linux

      Nota: Los comandos de esta sección solo se aplican a clientes de Linux. En la siguiente sección se proporcionan instrucciones para configurar clientes de Windows o macOS.

      Si su cliente cuenta con Linux, deberá realizar un cambio manual en su archivo /etc/sysctl.conf. Este cambio de configuración es necesario para modificar la perspectiva del kernel respecto de lo que es una ruta de retorno aceptable para el tráfico de su cliente. Debido a la forma en que se encuentra configurada la VPN de ZeroTier, a veces puede parecer que el tráfico que regresa de su servidor a su cliente proviene de una dirección de red diferente de aquella a la que se envió. Por defecto, el kernel de Linux considera que no son válidas y las desactiva, lo que hace necesario anular este comportamiento.

      Abra /etc/sysctl.conf en su máquina cliente:

      • sudo nano /etc/sysctl.conf

      A continuación, añada la siguiente línea:

      Output

      . . . net.ipv4.conf.all.rp_filter=2

      Guarde y cierre el archivo, y luego ejecute sudo sysctl -p para aplicar los cambios.

      A continuación, informe al software del cliente de ZerTier que su red tiene permiso para llevar tráfico de ruta predeterminado. Esto modifica el direccionamiento del cliente y, por tanto, se considera como una función privilegiada, por lo que debe habilitarse manualmente. El comando imprimirá una estructura de configuración en el resultado. Compruebe esto para confirmar que muestre allowDefault=1 en la parte superior:

      • sudo zerotier-cli set NetworkID allowDefault=1

      Si en cualquier momento desea dejar de usar ZeroTier como VPN con todo el enrutamiento de su tráfico a través de ella, fije allowDefault de nuevo en 0.

      • sudo zerotier-cli set NetworkID allowDefault=0

      Cada vez que se reinicia el servicio ZeroTier en el cliente, el valor allowDefault=1 vuelve a fijarse en 0. Por lo tanto, recuerde volver a ejecutarlo para activar la funcionalidad de VPN.

      Por defecto, el servicio de ZeroTier se establece para que se inicie automáticamente en el arranque para el cliente y el servidor de Linux. Si no desea que esto sea así, puede deshabilitar la rutina de inicio con el comando siguiente.

      • sudo systemctl disable zerotier-one

      Si desea usar otros sistemas operativos en su red ZeroTier, lea la siguiente sección. De lo contrario, continúe directamente con la sección “Administrar flujos”.

      Configurar clientes que no tengan Linux

      El software cliente de ZeroTier está disponible para muchos sistemas operativos, no solo para Linux; incluso es compatible con teléfonos inteligentes. Existen clientes para Windows, macOS, Android, iOS e incluso sistemas operativos especializados como QNAP, Synology y sistemas NAS de WesternDigital.

      Para unir clientes macOS y Windows a la red, inicie la herramienta ZeroTier (que instaló en el paso 1) e introduzca su ID de red en el campo proporcionado antes de hacer clic en Join. Recuerde volver a la consola de ZeroTier para seleccionar el botón Allow a fin de autorizar un nuevo host en su red.

      Asegúrese de seleccionar la casilla con la etiqueta Route all traffic through ZeroTier. Si no lo hace, su cliente se adjuntará a su red de ZeroTier, pero no intentará enviar su tráfico de Internet a través de ella.

      Utilice una herramienta de verificación de IP, como ICanHazIP para verificar que su tráfico aparezca a Internet desde la IP de su servidor. Para comprobarlo, pegue la siguiente URL en la barra de direcciones de su navegador. Este sitio web mostrará la dirección IP que su servidor (y el resto de Internet) ve que usted usa para acceder al sitio:

      http://icanhazip.com
      

      Una vez completados estos pasos, podrá comenzar a usar su VPN como lo desee. En la siguiente sección opcional, se abarca una tecnología integrada en la SDN de ZeroTier y conocida con la denominación “reglas de flujo”; no obstante, estas no son necesarias para que la funcionalidad de VPN se aplique.

      Paso 6: Administrar flujos (opcional)

      Uno de los beneficios de una red definida por software es el controlador centralizado. En cuanto a ZeroTier, el controlador centralizado es la Interfaz de usuario web que se sitúa por encima del servicio SDN general de ZeroTier. Desde esta interfaz, es posible escribir reglas conocidas como reglas de flujo que especifican lo que el tráfico de una red puede o no hacer. Por ejemplo, podría especificar una prohibición total en ciertos puertos de la red por los que pase tráfico a través la red, limitar los hosts que pueden comunicarse entre ellos e incluso redirigir el tráfico.

      Ésta es una capacidad extremadamente potente que se implementa casi al instante, ya que cualquier cambio aplicado a la tabla de flujos se envían a miembros de la red y surten efecto tras unos momentos. Para editar las reglas de flujo, vuelva a la interfaz de usuario web de ZeroTier, haga clic en la pestaña Networking, y desplácese hacia abajo hasta que vea un cuadro titulado Flow Rules (puede estar contraído, en cuyo caso deberá desplegarlo). Con esto, se abrirá un campo de texto en el que podrá introducir las reglas que desee. Existe, en la consola de ZeroTier, un manual completo en un cuadro que se halla justo debajo del cuadro de entrada de Flow Rules; lleva la leyenda Rules Engine Help.

      A continuación, se ofrecen algunas reglas de ejemplo para ayudarlo a explorar esta funcionalidad.

      Para bloquear cualquier tráfico vinculado al servidor DNS 8.8.8.8, añada esta regla:

      drop
          ipdest 8.8.8.8/32
      ;
      

      Para redirigir cualquier tráfico destinado al servidor de DNS público de Google a uno de sus nodos de ZeroTier, añada la regla siguiente. Esto podría servir como una regla general excelente para anular las búsquedas de DNS:

      redirect NetworkID
          ipdest 8.8.8.8/32
      ;
      

      Si su red tiene requisitos de seguridad especiales, puede detener cualquier actividad en los puertos FTP, Telnet y HTTP sin cifrado añadiendo esta regla:

      drop
          dport 80,23,21,20
      ;
      

      Cuando termine de añadir las reglas de flujo, haga clic en el botón Save Changes. ZeroTier registrará sus cambios.

      Conclusión

      A lo largo de este tutorial, dio un primer paso hacia el mundo de las redes definidas por software. Además, trabajar con ZeroTier proporciona cierta información sobre los beneficios de esta tecnología. Si siguió el ejemplo de VPN, aunque la configuración inicial puede contrastar con otras herramientas que haya usado en el pasado, la facilidad de añadir clientes podría ser una razón de peso para usar la tecnología en cualquier otro espacio.

      En resumen, aprendió a usar ZeroTier como su proveedor de SDN, y a configurar y conectar nodos a esa red. El elemento de VPN le habrá proporcionado un mayor nivel de comprensión de cómo funciona el direccionamiento en esa red y cualquier ruta de este tutorial le permitirá utilizar la potente tecnología de las reglas de flujo.

      Ahora que existe una red punto a punto, podría combinarla con otra funcionalidad como la de intercambio de archivos. Si dispone de un servidor NAS o de archivos en casa, podría vincularlo a ZeroTier y acceder a él en cualquier parte. Si desea compartirlo con sus amigos, puede mostrarles la forma de unirse a su red de ZeroTier. Los empleados distribuidos en una zona extensa podrían incluso establecer conexión con el mismo espacio central de almacenamiento. Si desea comenzar a compilar el intercambio de archivos para cualquiera de estos ejemplos, consulte Cómo configurar un recurso compartido de Samba para una pequeña organización en Ubuntu 16.04.



      Source link