
Aún cuando los trabajos QZDASOINIT existen desde hace muchos años permitiéndonos conectar mediante ODBC o JDBC ha sido en los últimos años, desde V6R1 , que hemos visto un incremento de este tipo de conexiones, particularmente de servidores y procesos de extracción de datos.
Y a medida que tenemos más conexiones también se incrementa la complejidad de las conexiones y la dificultad para controlar quien se conecta, en que horario, con qué mecanismo, etc.
Mucha de esta información se puede obtener empleando el journal de auditoría del sistema, un producto muy conocido y no tan usado. Sin embargo la información que provee el journal puede ser algo confusa y no siempre brinda todo el contenido que necesitamos y por otro lado no nos permite tomar acción, como podría ser evitando esa conexión si no cumple con ciertas reglas definidas por nosotros.
IBM nos brinda EXIT POINTS para controlar las comunicaciones a la base de datos (y muchas cosas más), los cuales podemos usar para monitorear o filtrar estas conexiones mediante un EXIT POINT PROGRAM.
Existen varios de estos EXIT POINTS para controlar las conexiones a la base de datos, pero sólo nos enfocaremos en las conexiones remotas mediante QIBM_QZDA_INIT .
Se pueden controlar también los comandos SQL y otros tipos de conexión, pero si no somos cuidadosos podríamos hacer más lentas nuestras aplicaciones. Mi recomendación es que usen productos comerciales si tienen necesidades de controlar las sentencias SQL o ejecución de Stored Procedures. Hay productos como Data Thread de HelpSystems que hacen su tarea de forma muy eficiente y simple.
Este es un ejemplo de cómo guardar información de la conexión. Adaptar este CL para filtrar por valores de IP, Usuario, Horario, etc lo dejo a criterio del lector, ya que no es tan complejo partiendo de este ejemplo.
Este CL se basa en el publicado por Michael Swenson en IBM System Magazine
PGM PARM(&STATUS &REQUEST)
/********************************************************************/
/* Declaracion de parametros */
/********************************************************************/
DCL VAR(&STATUS) TYPE(*CHAR) LEN(1) /* ACCEPT OR REJECT */
DCL VAR(&REQUEST) TYPE(*CHAR) LEN(2000) /* PARAMETER STRUCTURE */
/********************************************************************/
/* Declaracion de variables */
/********************************************************************/
DCL VAR(&USER) TYPE(*CHAR) LEN(10) /* USER ID */
DCL VAR(&ITYPE) TYPE(*CHAR) LEN(63) /* Interface type */
DCL VAR(&INAME) TYPE(*CHAR) LEN(127) /* Interface name */
DCL VAR(&ILEVEL) TYPE(*CHAR) LEN(63) /* Interface level */
DCL VAR(&STMT) TYPE(*CHAR) LEN(512) /* Insert statement */
DCL VAR(&CMD) TYPE(*CHAR) LEN(512) /* Comando QSHELL */
DCL VAR(&RCVVAR) TYPE(*CHAR) LEN(332)
DCL VAR(&RCVLEN) TYPE(*CHAR) LEN(4)
DCL VAR(&FMTNAM) TYPE(*CHAR) LEN(8) VALUE('JOBI0600')
DCL VAR(&JOBNAM) TYPE(*CHAR) LEN(26) VALUE('*')
DCL VAR(&INTJOB) TYPE(*CHAR) LEN(16)
DCL VAR(&JOBNUM) TYPE(*CHAR) LEN(8)
DCL VAR(&JOB_IP) TYPE(*CHAR) LEN(15)
DCL VAR(&JOB_NAME) TYPE(*CHAR) LEN(10)
DCL VAR(&JOB_NBR) TYPE(*CHAR) LEN(6)
DCL VAR(&JOB_ID) TYPE(*CHAR) LEN(30)
DCL VAR(&JOB_USER) TYPE(*CHAR) LEN(10)
DCL VAR(&Q) TYPE(*CHAR) LEN(1) VALUE('''')
/********************************************************************/
/* Extraigo las variables del parametro */
/********************************************************************/
CHGVAR VAR(&USER) VALUE(%SST(&REQUEST 1 10))
CHGVAR VAR(&ITYPE) VALUE(%SST(&REQUEST 33 63))
CHGVAR VAR(&INAME) VALUE(%SST(&REQUEST 96 127))
CHGVAR VAR(&ILEVEL) VALUE(%SST(&REQUEST 223 63))
CHGVAR VAR(&STATUS) VALUE('1') /* Aceptar conexion */
CHGVAR VAR(%SST(&RCVVAR 129 1)) VALUE('X')
CHGVAR VAR(%BIN(&RCVLEN)) VALUE(332)
/******************************************************************/
/* Recupero Job & IP */
/******************************************************************/
RTVJOBA JOB(&JOB_NAME) USER(&JOB_USER) NBR(&JOB_NBR)
CHGVAR VAR(&JOB_ID) VALUE(&JOB_NBR *TCAT '/' +
*TCAT &JOB_USER *TCAT '/' *TCAT &JOB_NAME)
CALL PGM(QSYS/QUSRJOBI) +
PARM(&RCVVAR &RCVLEN &FMTNAM &JOBNAM &INTJOB)
CHGVAR VAR(&JOB_IP) VALUE(%SST(&RCVVAR 308 15))
/******************************************************************/
CHGVAR VAR(&STMT) VALUE(' INSERT INTO DBLOG.DBINITDATA ' *CAT +
'Values (CURRENT_TIMESTAMP, ' *CAT &Q *CAT &USER *TCAT &Q +
*CAT ', ' *CAT &Q *CAT &ITYPE *TCAT &Q *CAT ', ' *CAT &Q +
*CAT &INAME *TCAT &Q *CAT ', ' *CAT &Q *CAT &ILEVEL +
*TCAT &Q *CAT ', ' *CAT &Q *TCAT &JOB_ID *TCAT &Q +
*CAT ', ' *CAT &Q *TCAT &JOB_IP *TCAT &Q *CAT ' ) ')
RUNSQL SQL(&STMT) COMMIT(*NONE) NAMING(*SQL)
MONMSG MSGID(CPF0000)
ENDPGM
Luego creamos la biblioteca DBLOG y el archivo DBINITDATA con la siguiente estructura:
ConnectionTime timestamp, User CHAR(10), InterfaceType CHAR(63), InterfaceName CHAR(127), InterfaceLevel CHAR(63), JOB_ID CHAR(30), JOB_IP CHAR(30))
y asignamos permisos :
GRTOBJAUT OBJ(DBLOG/DBINITDATA) OBJTYPE(*FILE) USER(QUSER)
Ahora conectamos el EXIT POINT :
ADDEXITPGM EXITPNT(QIBM_QZDA_INIT) FORMAT(ZDAI0100) PGMNBR(1) PGM(ESSELWARE/ZDAINIT) TEXT('Registro conexiones ODBC/JDBC')
Finalmente debemos bajar el HOST Server *DATABASE y los QZDASOINIT. Sin embargo, lo ideal es bajar TODOS los servicios o dar un IPL.
Manipulando la variable &STATUS podemos permitir la conexión o rechazarla (1 o 0).
Vuelvo a insistir, se pueden hacer programas para controlar las instrucciones SQL sin mucha complicación, pero la latencia que podría agregar el programa podría afectar negativamente el rendimiento de la base de datos. Recomiendo que consideren productos comerciales en esos casos.
Mucha suerte