Why Linux is not responding – it’s the flaming file-wall!

I could not ping my Linux Server, and could not issue a traceroute command. It turns out the firewall was blocking the traceroute flow.

This blog posts describes how I checked this, and fixed the firewall problem.

Traceroute sends (by default) a UDP packet to a port address in the range 33434-33523. It usually responds with a “timed out” type response. If there is no response then there is a good chance that the packet is being dropped by a firewall.

See Understanding traceroute (or tracerte).

Using wireshark I could see UDP packets going in to my Linux, but there was no corresponding reply being returned.

When traceroute worked I got the out inbound UDP packet, and the outbound response with “destination unreachable” (which looks like a problem but actually shows normal behaviour) as shown in the data below. Wireshark highlights it with a black background, because it thinks it is a problem.

SourceDestinationDst PortportProtocolInfo
2001:db8::22001:db8::73343452119UDP52119 → 33434 Len=24
2001:db8::7 2001:db8::7 33434 52119 ICMPV6 Destination Unreachable (Port unreachable)

When traceroute failed I only got the inbound UDP packet

SourceDestinationDst PortportProtocolInfo
2001:db8::22001:db8::73343452119UDP52119 → 33434 Len=24

If the packets is blocked by a firewall, then the traceroute output will have “*” as the node name.

Useful Fire Wall (ufw) is documented here.

I was on Ubuntu Linux 20.04.

Display the status of the firewall

sudo ufw status verbose

This gave me

Status: active
Logging: off (low)
Default: deny (incoming), allow (outgoing), deny (routed)
New profiles: skip

To                         Action      From
--                         ------      ----
Anywhere                   ALLOW IN    10.1.1.2                  
22/tcp                     ALLOW IN    Anywhere                  
20,21,10000:10100/tcp      ALLOW IN    Anywhere                  
21/tcp                     ALLOW IN    Anywhere                  
20/tcp                     ALLOW IN    Anywhere                  
22/tcp (v6)                ALLOW IN    Anywhere (v6)             
20,21,10000:10100/tcp (v6) ALLOW IN    Anywhere (v6)             
21/tcp (v6)                ALLOW IN    Anywhere (v6)             
20/tcp (v6)                ALLOW IN    Anywhere (v6)         

By default,

  • incoming data is blocked
  • outbound data is allowed
  • routed data is blocked.

Logging is off, and problems are not reported.

The displays shows there are no rules for UDP – so any incoming UDP request is blocked (quietly dropped = dropped without telling anyone).

You may want to issue the command and pipe the output to a file, ufw.txt, to keep a record of the status before you make any changes. If you make any changes, they persist – even across reboot.

Enable logging to see what is being blocked

sudo ufw logging on

Rerun your traceroute or command.

At the bottom of /var/log/ufw I had (this has been reformatted to make it display better)

Nov 28 12:27:43 colinpaice kernel: [ 3317.641508] [UFW BLOCK] IN=enp0s31f6 OUT= MAC=8c:16:45:36:f4:8a:00:d8:61:e9:31:2a:86:dd SRC=2001:0db8:0000:0000:0000:0000:0000:0002 DST=2001:0db8:0000:0000:0000:0000:0000:0007
LEN=80
TC=0
HOPLIMIT=1
FLOWLBL=924186
PROTO=UDP
SPT=48582
DPT=33434
LEN=40

Wireshark gave me

Frame 4: 94 bytes on wire (752 bits), 94 bytes captured (752 bits) on interface enp0s31f6, id 0   
Ethernet II, Src: Micro-St_e9:31:2a (00:d8:61:e9:31:2a), Dst: LCFCHeFe_36:f4:8a (8c:16:45:36:f4:8a)
Internet Protocol Version 6, Src: 2001:db8::2, Dst: 2001:db8::7
    0110 .... = Version: 6
    .... 0000 0000 .... .... .... .... .... = Traffic Class: 0x00 
    .... .... .... 1110 0001 1010 0001 1010 = Flow Label: 0xe1a1a
    Payload Length: 40
    Next Header: UDP (17)
    Hop Limit: 1
    Source: 2001:db8::2
    Destination: 2001:db8::7
User Datagram Protocol, Src Port: 48582, Dst Port: 33434
    Source Port: 48582
    Destination Port: 33434
    Length: 40
    Checksum: 0x6ebd [unverified]
    [Checksum Status: Unverified]
    [Stream index: 0]
    [Timestamps]
Data (32 bytes)

From this, we can see the fields match up

  • flow label (0xe1a1a = 924186)
  • source 2001:db8::2 = 2001:0db8:0000:0000:0000:0000:0000:0002
  • destination 2001:db8::7 = 2001:0db8:0000:0000:0000:0000:0000:0007
  • source port 48582
  • destination port 33434.

Port 33434 is used by traceroute, so this is a good clue this is a traceroute packet.

The reason the record was written to the log is [UFW BLOCK]. The firewall blocked it.

The request came in over interface enp0s31f6.

How to enable it.

You can specify different filters, and granularity of parameters.

For example

  • sudo ufw rule allow log proto udp from 2001:db8::2
  • sudo ufw rule allow log in on enp0s31f6 log comment ‘colin-ethernet’
  • sudo ufw rule allow log proto udp to 2001:db8::7 port 33434:33523 from 2001:db8::2

Where enp0s31f6 is the name of the ethernet link where the traffic comes from.

When running with either of these, I had in the log file

Nov 28 17:03:12 colinpaice kernel: [19847.112045] 
[UFW ALLOW] 
IN=enp0s31f6 OUT= MAC=8c:16:45:36:f4:8a:00:d8:61:e9:31:2a:86:dd SRC=2001:0db8:0001:0000:0000:0000:0000:0009 
DST=2001:0db8:0000:0000:0000:0000:0000:0007 
LEN=60 TC=0 HOPLIMIT=1 FLOWLBL=0 PROTO=UDP SPT=33434 DPT=33440 LEN=20

and the traceroute worked.

Note: The comment ‘…’ is an administration aid to give a description. It does not come out in the logs.

Display the rules

sudo ufw status numbered

gave

Status: active

     To                         Action      From
     --                         ------      ----
[ 1] Anywhere                   ALLOW IN    10.1.1.2                  
[ 2] 22/tcp                     ALLOW IN    Anywhere                  
[ 3] 20,21,10000:10100/tcp      ALLOW IN    Anywhere                  
[ 4] 21/tcp                     ALLOW IN    Anywhere                  
[ 5] 20/tcp                     ALLOW IN    Anywhere                  
[ 6] Anywhere on enp0s31f6      ALLOW IN    Anywhere                   (log)
[ 7] 22/tcp (v6)                ALLOW IN    Anywhere (v6)             
[ 8] 20,21,10000:10100/tcp (v6) ALLOW IN    Anywhere (v6)             
[ 9] 21/tcp (v6)                ALLOW IN    Anywhere (v6)             
[10] 20/tcp (v6)                ALLOW IN    Anywhere (v6)             
[11] Anywhere (v6) on enp0s31f6 ALLOW IN    Anywhere (v6)              (log)
[12] 2001:db8::7 33434/udp      ALLOW IN    2001:db8::2                (log)

There is now a rule [12] for udp to 2001:db8::7 port 33434

You can use commands like

sudo ufw delete 6

to delete a row.

Note: Always display before delete. Having deleted the rule 6 – rule 7 now becomes rule 6, etc.

Now that it works…

Any changes to ufw are remembered across reboots.

You may want to turn off the logging, until the next problem

sudo ufw logging off

and remove the log from the fire wall rules, by deleting and re-adding the rule.

sudo ufw rule delete allow log proto udp from 2001:db8::2

sudo ufw rule allow proto udp from 2001:db8::2

Understanding traceroute (or tracerte)

I was trying to use traceroute to find the route between two nodes and I did not understand the output. Like many things, once you understand it, is obvious.

This is another of the little topics which I thought I understood, and found I did not.

For example

traceroute ibm.com

produces

traceroute to ibm.com (23.39.199.16), 30 hops max, 60 byte packets
 1  bthub.home (192.168.1.254)  4.139 ms  7.528 ms  10.629 ms
 2  * * *
 3  * * *

What does the “*” mean – and why are there 3 “*”?

Traceroute logic

At a conceptual level, the logic of traceroute is:

At the origin

  • Send a UDP packet over a link towards the remote node, with hop limit = 1.
  • Set a timer
  • Wait for the reply (with time out)

At an intermediate node

  • Set hop limit = hop limit -1
  • If hop limit = 0
    • then send a UDP packet back to the originator, giving the IP address of the intermediate node, and information like “Destination unreachable (Port unreachable)”, or “request timed out”.
    • else send the packet over a link towards the remote destination.

Back at the origin

  • Wait for the response. When the response arrives, stop the timer and calculate the duration.
  • Lookup the IP address of the intermediate node, to find the node name.
  • Display original hop count, the name of the intermediate node, IP address of the intermediate node, and duration of the request.

For example

1 colin.Linux.Server (2001:db8::2) 0.988 ms

This gives you information on the first hop in the chain.

Go to the next level.

You can take this further.

  • Repeat the operation multiple times. This allows you to get multiple response times, so you can see the range of responses times, and get an idea of the variation (or consistency) of the response time.
  • Repeat it with hop count = 2,3,4,5… . When the hop count is 1, you get information about the first hop, when the hop count is 2, you get information about the next hop etc.

For example for Linux

traceroute to 2001:db8:1::9 (2001:db8:1::9), 30 hops max, 80 byte packets
1 colin.Linux.Server (2001:db8::2)0.267 ms 0.207 ms 0.140 ms
2 Colin.zOS (2001:db8:1::9) 3.794 ms 6.215 ms 6.920 ms

It gets more interesting.

If you send multiple request, a node may decide to route the request down a different link, so you may get multiple IP addresses for each hop.

What if there is a problem?

Unknown address

Traceroute will report as much as it can. For example 2001:db8:1::10 does not exist.

traceroute to 2001:db8:1::10 (2001:db8:1::10), 30 hops max, 80 byte packets
1 colinpaice (2001:db8::7) 3053.091 ms !H 3052.807 ms !H

This reports as far as it got (colinpaice 2001:db8::7); and !H. On Linux you can have additional information (!H)

  • !H host unreachable
  • !N network unreachable
  • !P protocol unreachable
  • !S source route failed
  • !F fragmentation needed
  • !X communication administratively prohibited
  • !V host precedence violation
  • !C precedence cutoff in effect
  • !<num> ICMP unreachable code <num>

Lost or dropped packets

A intermediate node may not be able to send the response back, for example, a firewall may block (and drop) any UPD packets. The originator times-out waiting for the reply. In this case it reports “*” as the IP address, and cannot provide the duration of the requests. This can occur if the router does not support traceroute, there is no link back to the originator, or there is a firewall which drops packets (going out, or coming back).

More advanced requests

Specify a different home

By default traceroute uses the IP address of the connection it will use to send the packet.

For example I have a system with two interfaces

  • tap1,my end of the connection is 2001:db8:1::3 with the remote end having 2001:db8:1::9 (my z/OS)
  • eno1, my end of the connection is 2001:db8::2 with the remote end having 2001:db8::7 (my laptop)

If I use traceroute to my laptop, I can issue

traceroute 2001:db8::7

by default traceroute uses 2001:db8::2 as its starting point (the IP adddess of the direct connection). I can see this in the wireshark trace.

I can use traceroute to my laptop , and say start from the IP address of the connection to z/OS

traceroute6 -s 2001:db8:1::3 2001:db8::7

-s says use a different starting address 2001:db8:1::3 – corresponding to the link to z/OS as its starting point.

When I used this command, my request was blocked, as my firewall was configured to accept traffic from 2001:db8:2, and not from 2001:db8:1::3.

Make traceroute fail quicker

The traceroute defaults are to try a maximum of 30 hops and wait 5 seconds so you could wait for over 2 minutes if there was a problem). If you know your network is small (at most 3 hops) and responds in under a second, you can use

traceroute -6 -w 2 -q 5 -m 3 2001:db8::7

  • -6 for IP V6 (or just use traceroute6)
  • -w 2 wait for up to 2 seconds
  • -q 1 send out 1 UPD request on each hop
  • -m 3 a maximum of 3 hops.

On z/OS use the tracerte command

tso tracerte 2001:db8::7 (try 1 wait 1 max 2

Getting OMPROUTE to work on ADCD

While working on getting IP V6 to work, I had problems getting my routing on z/OS working properly. I spent a few days working with TCPIP dynamic routing. What I have written below is what I have learned, it may well be wrong!

The problem…

With TCPIP you can define static routes. For example

  BEGINRoutes 
  ; Destination        SubnetMask    FirstHop       LinkName    Size 
  ROUTE 9.114.209.0    255.255.255.0    =            ETH2   MTU 1492 
  ROUTE DEFAULT             10.1.1.1                 ETH1   MTU 1492 
  ROUTE DEFAULT6  FE80::8C46:FAFF:FE86:1721    IFPORTCP6  MTU 1492 
  ENDRoutes 

This says

  • To send data IP V4 address9.114.209.* go via the link ETH2.
  • Otherwise send all IPV4 traffic to link ETH1 which has address 10.1.1.
  • Send all IP6 traffic to link IFPORTCP6 – which has an IP address of FE80::8C46:FAFF:FE86:1721.

Maintaining lists like these quickly become unmanageable as the size of the network increases.

Dynamically finding the configuration

To solve this problem TCPIP was enhanced to allow the system to discover information. The OMPROUTE daemon manages this.

When OMPROUTE is started, it queries the TCPIP configuration. It merges this information with its configuration data, and sends a request out to participating interfaces “Hello – who are you connected to”. From this information it can build a pictures of the network.

The “Hello – who are you connected to” could produce a lot of output; you can get information about all the links and routers in your environment.

You can divide your network ( from an OMPROUTE perspective ) into areas, and so only routers within an area exchange information. The areas have a number like 1.1.1.1.

The main backbone has number 0.0.0.0 You can send requests between areas. Routers which connect an area to the backbone are called Area Border Routers.

An Area Border Router can be configured as a default route – if a router does not know where to send the packet, send it to the Area Border Router.

Where is this information stored?

It looks like this configuration information is stored in the TCPIP address space, because if you shut down OMPROUTE, the configuration persists. I do not think the information will be updated, until OMPROUTE is restarted.

Routing packets

When a packet needs to be sent to a destination it uses the information provided by OMPROUTE. It uses two algorithms,

  • OSPF -Open shortest path first. As the state of an element in the network changes – the change is broadcast to all the routers. This means a router can quickly respond to a configuration change.
  • RIP – Routing interface protocol. This uses the number of hops. (I would have thought this was the same as the shortest path.) A RIP router has a 30 second heartbeat with its connected networks. If it has not received a response after 180 seconds, it assumes the network link is down.

It looks like OSPF is the better protocol, it is faster to respond to changes, and listens to changes, rather than using a heartbeat, and looks like it scales better.

Creating OMPROUTE

The documentation is not the clearest. I think it assumes you are an expert before you start.

The IBM documentation is here.

My additional steps included

  • The …TCPIP(PROF2) had “520 UDP OROUTED ; RouteD Server”. This name needs to match your started task proc. Either change the TCPIP profile, or use OROUTED as your proc name.
  • OMPROUTE procedure needs a userid with an OMVS segment.
  • Create RACF started task profile. Profile OMPROUTE.* with CLASS(STARTED). STDATA INFORMATION user=…
  • I created USER.Z25A.tcpparms(omp) and copied TCPIP.SEZAINST(EZAORCFG) into it.
  • Initially I forgot to use define the RACF profile CLASS(OPERCMDS) MVS.ROUTEMGR.OMPROUTE

My OMPROUTE procedure was

//OMPROUTE PROC 
//OMPROUTE EXEC PGM=OMPROUTE,REGION=0M,TIME=NOLIMIT, 
// PARM=('ENVAR("_CEE_ENVFILE_S=DD:STDENV")/') 
//* 
//OMPCFG DD DISP=SHR,DSN=USER.Z25A.TCPPARMS(OMP) 
//STDENV DD * 
RESOLVER_CONFIG=//'ADCD.Z25A.TCPPARMS(TCPDATA)' 
OMPROUTE_DEBUG_FILE=/tmp/logs/omproute.debug 
OMPROUTE_IPV6_DEBUG_FILE=/tmp/logs/omprout6.debug 
OMPROUTE_DEBUG_FILE_CONTROL=1000,5 
//SYSPRINT DD SYSOUT=* 
//SYSOUT   DD SYSOUT=* 
//CEEDUMP  DD SYSOUT=*,DCB=(RECFM=FB,LRECL=132,BLKSIZE=132) 
//  PEND 

The OMPROUTE configuration is in //OMPCFG … USER.Z25A.TCPPARMS(OMP)

Setting up syslogd

If you are not running SYSLOGD, all of the console messages are prefixed with

BPXF024I (TCPIP) Oct 6 10:11:10 omproute 67174435 : …

When running with SYSLOGD, the default syslogd configuration is to write errors to a file (for example into /var/log/2022/10/06/errors) , and throws away the remainder. I added the following to my syslogd configuration and restarted syslogd.

*.OMPROUTE..* /var/log/%Y/%m/%d/omproute

The messages were then put into the file, and were like

Oct 6 11:52:19 S0W1 omproute[67174443]: EZZ7800I OMPROUTE starting
Oct 6 11:52:24 S0W1 omproute[67174443]: EZZ7817I Using defined OSPF protocol 89
Oct 6 11:52:24 S0W1 omproute[67174443]: EZZ7817I Using defined OSPF protocol 89
Oct 6 11:52:24 S0W1 omproute[67174443]: EZZ7838I Using configuration file: dd:OMPCFG=USER.Z25A.TCPPARMS(OMP)

After OMPROUTE started, In this file I had 19 messages. There were 6 message on the job log.

Configuring OMPROUTE

I had a TCPIP configuration with

INTERFACE IFPORTCP6 
  DEFINE IPAQENET6 
  CHPIDTYPE OSD 
  PORTNAME PORTCP 
  INTFID 7:7:7:7 
  IPADDR FE00::66:7:7:7 

DEVICE PORTB MPCIPA 
 LINK ETH2 IPAQENET PORTB 
HOME 172.26.1.9      ETH2 
                                                 
DEVICE PORTA MPCIPA 
 LINK ETH1 IPAQENET PORTA 
HOME 10.1.1.2        ETH1 
                                                 

In my configuration file I had

OSPF_INTERFACE 
       Attaches_to_Area =0.0.0.0 
       IP_Address=10.1.1.2 
       Subnet_mask=255.255.255.0 
       NAME=ETH1 
       ; 
RIP_INTERFACE 
       IP_Address=10.1.1.2 
       Subnet_mask=255.255.255.0 
       NAME=PORTA 
       ; 
IPv6_OSPF 
       RouterID = 7.7.7.7
       ; 
IPV6_OSPF_INTERFACE 
       Attaches_to_Area =0.0.0.0 
       NAME=IFPORTCP6 
       ; 
IPv6_RIP_Interface 
       Name = IFPORTCP6
       ; 

At startup I got messages in the job log

EZZ7871I NO MATCHING INTERFACE STATEMENTS FOR 172.26.1.20 (EZASAMEMVS)                        
EZZ8171I OMPROUTE IPV4 OSPF IS USING ASSIGNED ROUTER ID 10.1.1.2 FROM ETH1 INTERFACE          
EZZ8171I OMPROUTE IPV6 OSPF IS USING CONFIGURED ROUTER ID 7.7.7.7 FROM IPV6_OSPF STATEMENT     

To resolve the problem with EZASAMEMVS I added

 Interface 
      IP_Address=172.26.1.20 
      Name=EZASAMEMVS 
      subnet_mask=255.255.255.0 
      ; 

Which basically says this interface is not involved in any dynamic routing.

Once this was resolved the messages in the syslogd file were

EZZ7800I OMPROUTE starting
EZZ7817I Using defined OSPF protocol 89
EZZ7817I Using defined OSPF protocol 89
EZZ7838I Using configuration file: dd:OMPCFG=USER.Z25A.TCPPARMS(OMP)
EZZ7883I Processing interface from stack, address 10.1.1.2, name ETH1, index 5, flags 441
EZZ7883I Processing interface from stack, address 172.26.1.20, name EZASAMEMVS, index 2, flags ffff8c50
EZZ7871I No matching interface statements for 172.26.1.20 (EZASAMEMVS)
EZZ7977I Processing IPv6 interface from stack, address fe00::66:7:7:7, name IFPORTCP6, index 51, flags 1, flags2 0
EZZ7977I Processing IPv6 interface from stack, address fe80::7:7:7:7, name IFPORTCP6, index 51, flags 1, flags2 2
EZZ7882I Processing static route from stack, destination 9.114.209.0, Mask 255.255.255.0, gateway 0.0.0.0 , table EZBMAIN
EZZ7882I Processing static route from stack, destination 0.0.0.0, Mask 0.0.0.0, gateway 10.1.1.1 , table EZBMAIN
EZZ7882I Processing static route from stack, destination ::, prefixlen 0, gateway fe80::8c46:faff:fe86:1721 , table EZBMAIN
EZZ8023I The RIP routing protocol is Enabled
EZZ8036I The IPv6 RIP routing protocol is Enabled
EZZ8171I OMPROUTE IPv4 OSPF is using assigned router ID 10.1.1.2 from ETH1 interface
EZZ7937I The IPv4 OSPF routing protocol is Enabled
EZZ8171I OMPROUTE IPv6 OSPF is using configured router ID 7.7.7.7 from IPV6_OSPF statement
EZZ7937I The IPv6 OSPF routing protocol is Enabled
EZZ7898I OMPROUTE Initialization Complete

Displaying information from OMPROUTE

On the console

You can use commands like

f omproute,ospf,list,all
d tcpip,,omp,ospf,list,all

Both of which will list all information about the OSPF configuration.

There are three types of resource you an display

  • OSPF – d tcpip,,omp,ospf,list,all or d tcpip,,omp,IPV6ospf,list,all
  • RIP – d tcpip,,omp,rip,list,all or d tcpip,,omp,IPV6rip,list,all
  • Other interface – d tcpip,,omp,generic,all or d tcpip,,omp,generic6,all

From netstat

Once OMPROUTE was active NETSTAT ROUTE gave me

IPv4 Destinations
Destination        Gateway         Flags    Refcnt     Interface
-----------        -------         -----    ------     ---------
Default            10.1.1.1        UGS      0000000000 ETH1
9.114.209.0/24     0.0.0.0         US       0000000000 ETH1
10.1.1.0/24        0.0.0.0         UO       0000000000 ETH1
10.1.1.2/32        0.0.0.0         UH       0000000000 ETH1
127.0.0.1/32       0.0.0.0         UH       0000000002 LOOPBACK
172.26.1.20/32     0.0.0.0         H        0000000000 EZAZCX
172.26.1.20/32     0.0.0.0         H        0000000000 EZASAMEMVS
IPv6 Destinations
DestIP:   Default
  Gw:     fe80::8c46:faff:fe86:1721
  Intf:   IFPORTCP6         Refcnt:  0000000000
  Flgs:   UGS               MTU:     1492
DestIP:   ::1/128
  Gw:     ::
  Intf:   LOOPBACK6         Refcnt:  0000000000
  Flgs:   UH                MTU:     65535
DestIP:   fe00::66:7:7:7/128
  Gw:     ::
  Intf:   IFPORTCP6         Refcnt:  0000000000
  Flgs:   UH                MTU:     9000
DestIP:   fe80::7:7:7:7/128
  Gw:     ::
  Intf:   IFPORTCP6         Refcnt:  0000000000
  Flgs:   UH                MTU:     9000

Where key fields are

  • Flgs UO. U=The interface is UP, and The route was created by OSPF (includes OSPF external routes).

Secure X3270 to z/OS on ADCD

I was asked if it was possible to connect to an ADCD system using X3270 and certificates, after quite a bit of work, the answer is yes – but it may not be easy.

The process is documented in the September version of IBM ISV zPDT Guide and Reference – which works, but the SecurePort is being removed in z/OS 2.5!

How to connect using x3270.

Using a “dialed in” local terminal into an ADCD system.

You can connect to z/OS using 3270 like terminals via a 3274 type controller and use applications like TSO. This is not a TCPIP connection, so you cannot use TLS to protect the session. These terminals are created using a Linux command like

x3270 -model 5 colin@localhost:3270 &

Where the :3270 matches the zPDT configuration statement 3270port 3270.

The colin@, known as the LUName, is put in the title of the window (so I could hot key to it, by setting key Ctrl+3 to wmctrl -a colin@).

Using X3270 and TCPIP over an insecure connection

You can connect over TCPIP into the TN3270 server using a command like

x3270 -model 5 10.1.1.2:23

This uses port 23, the standard telnet port.

You can specify an LU name – but you need to look at your TN3270 configuration to see what values have been configured. If you do not know what you are doing … it is safer to omit it.

SECUREPORT will be removed in z/OS 2.5

This was the “secure” way of providing a secure connection, before AT-TLS was developed. It is documented in Appendix E of IBM ISV zPDT Guide and Reference

The z/OS documentation says SECUREPORT will be removed

Keyword no longer supported for the TN3270E Telnet server: Removal of native
TLS/SSL support from TN3270E Telnet Server
, FTP Server, and DCAS.

How to configure and use TN3270

Ive written about it here.

My TN3270 configuration is member TNPO2023 is

TelnetParms         ; ATTLS defined secure port 
 TTLSPort 2023      ; 
 DEBUG CONN DETAIL CTRACE 
 DEBUG CONN trace  CTRACE 
 ConnType Secure    ; Client chooses secure or nonsecure connection. 
EndTelnetParms 
                                                                           
BeginVTAM 
 Port 2023 
 DEFAULTLUS 
   TLS00001..TLS00030 
 ENDDEFAULTLUS 
 ALLOWAPPL TSO* DISCONNECTABLE ; Allow all users access to TSO 
             ; applications. 
             ; TSO is multiple applications all beginning with TSO, 
             ; so use the * to get them all.  
 ALLOWAPPL *      ; Allow all applications that have not been 
                  ; previously specified to be accessed.             
 USSTCP USSN 
EndVTAM 

Using AT-TLS

I eventually got a secure connection using AT-TLS. Many parameters need to be correct for the TLS Handshake to work. Some combinations should work – but did not.

I’ve blogged about setting up and using AT-TLS.

The short list of requirements:

  • The z/OS certificate needs CN(‘10.1.1.2’) where 10.1.1.2 is what is used by the X3270 client. It checks the value in the certificate with the value used in the connection. ALTNAME(IP(10.1.1.2)) did not work for me. If there is a mismatch you get x3270 message “hostname mismatch(62). When I used a host name of zos as in “x3270…. zos” – and the z/OS certificate has CN(‘zos’)…. it also worked.
  • You can use RSA, and NISTECC, certificates on z/OS.
    • TLS 1.2 or TLS 1.3 , RSA size 2048 or larger
    • TLS 1.2 or TLS 1.3, NISTECC size 521
    • BPECC not supported.
  • The CA was exported, sent down to Linux and used in the x3270 command (and also the openssl s_client command). For example -cafile ./doczosca.pem .
  • x3270 does not use a certificate on Linux – the doc implies it does, but nothing gets sent to the server.
  • In the AT-TLS configuration below,
    • the three cipher spec represent TLS 1.3, NISTECC and RSA.
    • ApplicationControlled On is required
    • HandshakeRole Server is required

Below is the AT-TLS configuration for my telnet (TN…) configuration. It should work with the keyring created in Appendix E. Secure x3270 connection in IBM ISV zPDT Guide and Reference September 2022 (SG24-8205-06). See JCL. The file below is on GIT.

TTLSRule                      TN 
{ 
  LocalPortRange              2023 
  Jobname                     TN3270 
  Direction                   INBOUND 
  TTLSConnectionActionRef     TNCA   
  TTLSGroupActionRef          TNGA 
  TTLSEnvironmentActionRef    TNEA 

} 
TTLSConnectionAction              TNCA 
{ 
  TTLSCipherParmsRef              TLS13TLS12 
  TTLSSignatureParmsRef           TNESigParms 
  TTLSConnectionAdvancedParmsRef  TNCOonAdvParms 
  CtraceClearText                 Off 
  Trace                           50 
} 
TTLSConnectionAdvancedParms       TNCOonAdvParms 
{ 
 #ServerCertificateLabel  NISTECC521 
 #ServerCertificateLabel  RSA2048 
 #ccp this was added 
  ApplicationControlled         On 
  SSLv3          OFF 
  TLSv1          OFF 
  TLSv1.1        OFF 
  TLSv1.2        ON 
  TLSv1.3        OFF 
  SecondaryMap   OFF 
  HandshakeTimeout 3 
} 

TTLSGroupAction      TNGA 
{ 
  TTLSEnabled        ON 
  trace              50 
} 
TTLSKeyringParms    TNKEYRING 
{ 
  Keyring           START1/TN3270 
} 

TTLSEnvironmentAction      TNEA 
{ 
  HandshakeRole            Server 
  TTLSKeyringParms 
  { 
#    Keyring                START1/TN3270 
# Use the keyring from the ZPDT documentation chapter E
     Keyring                START1/TN3270TLSring 
  } 
  TTLSSignatureParmsRef    TNESigParms 
} 
TTLSSignatureParms         TNESigParms 
{ 
   CLientECurves Any 
} 
TTLSCipherParms             TLS13TLS12 
{ 
#TLS 1.3 
 V3CipherSuites      TLS_CHACHA20_POLY1305_SHA256 
#V3CipherSuites      TLS_AES_256_GCM_SHA384 
#V3CipherSuites      TLS_AES_128_GCM_SHA256 
#TLS 1.2 
# NSTECC 
 V3CipherSuites      TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 
#RSA 
 V3CipherSuites      TLS_RSA_WITH_AES_256_CBC_SHA256 
} 

I did many system SSL traces to get it working.

Some lessons learned

  • Although you can specify a certificate and private key on the Linux x3270 command, it does not use them. If you specify them, the certificate is not passed up to to z/OS.
  • The AT-TLS configuration needs TTLSEnvironmentAction -> HandshakeRole SERVER. (Despite what the documentation says). If you specify HandshakeRole ServerWithClientAuth, then z/OS expects the client to send a certificate as part of the handshake – and as x3270 does not sent a certificate – the handshake fails.
  • x3270 checks the host name. In the z/OS certificate the DN needs a CN matching the connection name. I connected to 10.1.1.2 – I needed SUBJECTSDN(CN(‘10.1.1.2‘) … . Without this you get hostname mismatch (62).
    • You should be able to specify RACDCERT …. ALTNAME(IP(10.1.1.2)), as an alternate name, but x3270 does not recognise it.
  • x3270 supports TLS 1.3 – if you have TLS 1.3 cipher specs configured in AT-TLS, and specify TLSv1.3 ON
  • X3270 supports TLS 1.2 – if you have TLS 1.2 cipher specs configured in AT-TLS, and specify TLSv1.2 ON and TLSv1.3 OFF.
  • x3270 sends up a list of cipher suites it will accept. The first three are TLS 1.3 (TLS_AES_256_GCM_SHA384 (0x1302) ,TLS_CHACHA20_POLY1305_SHA256 (0x1303),TLS_AES_128_GCM_SHA256 (0x1301).
  • When configuring TN3270 use V3CipherSuites not V3CipherSuites4char. V3CipherSuites takes 2 character strings and long TLS_… strings. V3CipherSuites4char only take 4 character strings, and not TLS_… strings.
  • If you change the PAGENT configuration you need F PAGNET,UPDATE to pick up the changes.
  • If you make a change to the PAGENT configuration, it does not always report problems. You should use Unix command commands like pagent -t -f TN 1>a … oedit a to display the TTLS configuration for rule TN, and edit the file to check.
  • If you change a keyring, you need F CPAGENT,REFRESH to pick up the change.
  • When you start PAGENT use the -l /var/log/pagent.log -d1 options (or similar). Review the /var/log/pagent.log file and check for “WARNING” and “ERR”
  • The PAGENT configuration can have the same parameter specified at the environment level and at the connection level. The pasearch -t -f TN command displays both sets of data … you have to be careful you are checking the right set of data.

Is the port active?

Check the port is being listened to

tso netstat conn ( port 2023

gave

EZZ2585I User Id  Conn     Local Socket           Foreign Socket         State
EZZ2586I -------  ----     ------------           --------------         -----
EZZ2587I TN3270   0000000B 0.0.0.0..2023          0.0.0.0..0             Listen

Showing the port is in Listen state from jobname TN3270 (which has userid TCPIP!)

Update to show it not working!

I was asked a question about AT-TLS, and it not working. I thought it would be useful to include some Wireshark output to help people to see what is happening.

I used x3270 10.1.1.2@3023 and it reported “SSL: Host certificate verification failed: self signed certificate in certificate chain”.

In the examples below there are three records of interest

  • Client Hello – this is the first step in the handshake. If you do not have this – your client is not sending a request
  • Server Hello – the back-end has processed the Client-Hello – and, in the example below, sends down a certificate
  • Alert (from the client). The client cannot validate the certificate because it does not have the CA for the certificate.

The Wireshark trace was

The important line is the “Client Hello” in blue. This is the start of the TLS handshake. In my case the length is 512 bytes. I would expect any TLS handshake to be a couple of hundred bytes long. If you do not get a “Client Hello”, your client is not set up for TLS/SSL.

The “Server Hello” line is where the server is responding (with a certificate).

There is an error “Alert (Level: Fatal Description: Unknown CA”

Using AT-TLS and PAGENT on z/OS (with ADCD)

I wrote this post based on getting X3270 to work with TLS to z/OS. It covers some of the lessons I learned in doing so.

Policy Server

The Communications Server’s policy server allows you to define policies for: (the list below is mainly taken from the IBM documentation)

  • QoS: The overall Quality of Service provided to applications or users, in terms of elements such as throughput and delay. It might be critical to provide Business Application traffic better service during peak hours than that of FTP or web traffic.
  • IDS: Intrusion Detection Services provides the following support: scan detection and reporting, attack detection, reporting, and prevention, traffic regulation for TCP connections and UDP receive queues. You can use IDS policies to specify event conditions and the actions to take for particular events
  • IPSec: IP Security policy can be used for the following protection:
    • Protect a secure host on an internal network from unwanted network traffic
    • Provide protection for traffic between partner companies over connected networks
    • Allow secure sending of data over the Internet by providing IPSec virtual private network (VPN) support
  • Routing: Policy conditions consist of a variety of selection criteria that act as filters for policy-based routing (Routing) rules. Traffic can be filtered based on source addresses, destination addresses, source port range, destination port range, protocol, job name, security zone, and security label.
  • AT-TLS: (Application Transparent-Transport Layer Security) Provides TLS support at the TCPIP level (below the application). Using AT-TLS means applications do not need to be changed to support TLS.

The PAGENT (Policy Agent) started task runs the policy server. It can use local configuration files, or data in LDAP.

Using AT-TLS

It was a struggle to get a secure connection using AT-TLS and x3270. Many parameters need to be correct for the TLS Handshake to work. Some combinations should work – but did not, the documentation is not 100% correct. When I knew what the correct parameters were, the configuration was pretty easy! The configuration technique looks as if it was designed for a baby system. It is not easy to follow good housekeeping, and change management practices, which made the overall experience harder than I expected.

X3270 requirements

x3270 is a 3270 emulator. It can use TLS to provide a secure connection to z/OS. Although you can specify a certificate for X3270 to use – x3270 does not used the client certificate.

At a high level, the TLS flow between x3270 and AT-TLS is:

  • X3270 client sends a “client-hello” request to the server. This includes what levels of TLS are supported (TLS 1.2, TLS 1.3), and the cipher specs it supports (what encryption type,what checksum algorithm etc)
  • The server (Pagent) matches the information sent in the “Client-hello” with its configuration. For example, select a certificate which matches the encryption type, and finds a common cipher spec.
  • If there is an acceptable certificate, and cipher spec, the selected certificate and selected cipher spec are sent down to the client (“server hello”).
  • The x3270 client checks that the certificate is acceptable – the CN in the certificate matches the address of the server. (CN(10.1.1.2) matches the IP address 10.1.1.2).
  • If client authentication is requested, then the client sends its certificate to the server. This is not supported by X3270, and the server has to be configured with HandshakeRole Server.

X3270 initially sends that it can support TLS 1.2 and TLS 1.3, and a variety of cipher specs.

TN3270 requirements

Not all certificates worked. I could only get certificates to work with

  • RSA key size >= 2048
  • NISTECC leysize >= 521

To AT-TLS, this is just a certificate name in a keyring.

In the AT-TLS configuration

  • ApplicationControlled On is required. This allows TN3270 to interact with AT-TLS, for example display the cipher spec being used.
  • HandshakeRole Server is required.
  • It needs a keyring, and access to the private part of the certificate. For example CONTROL access to the RACF profile userid.ring.LST int the RDATALIB class.
  • Certificates
    • If you do not specify a certificate – it takes the keyring default.
    • You can specify a(one) certificatelabel.
    • You can specify multiple ServerCertificateLabel statements. With this you can support different certificate types, and support migration to newer certificates.

AT-TLS configuration – in general

The Communications Server as a group of products, do not have a consistent way of configuring the individual components. For example some use # as a comment delimiter, other products use ; . Configuring the Policy Server is not difficult – just different, and does not behave as other z/OS components do, or as I expected.

In my PAGENT JCL is

//STDENV -> USER.Z24C.TCPPARMS(PAGENTEN).

This file has

PAGENT_CONFIG_FILE=//'USER.Z24C.TCPPARMS(PAGENTCF)' 
LIBPATH=/usr/lib 

The PAGENTCF member is like

CommonTTLSConfig //'USER.Z24C.TCPPARMS(PAGENTCO)' 
tcpImage TCPIP   //'USER.Z24C.TCPPARMS(PAGENTT)' 
tcpImage TCPIP1  //'USER.Z24C.TCPPARMS(PAGENT1)' 

File USER.Z24C.TCPPARMS(PAGENTT) has the configuration for one TCPIP image.

TTLSConfig //'USER.Z24C.TCPPARMS(PAGENTTN)' FLUSH PURGE 
TTLSRULE ... #and other inline definitions 

QOSConfig  //'USER.Z24C.TCPPARMS(PAGENTQ1)' FLUSH PURGE 
policyAction  ...  # and other inline QOS definitions 

# and similarly for IDS, IPSec,Routing etc

You are allowed one TTLSConfig statement per TCPIP file. If you have multiple, only the last one will be used. You can have multiple TTLSRULE statements.

How the configuration works

Within a file, if you have a set of definitions with the same name, the last one will be used. For example

TTLSEnvironmentAction                 TNEA 
{ 
  TTLSKeyringParms 
  { 
    Keyring                   START1/TN3270 
  } 
  Trace 17
} 
TTLSEnvironmentAction                 TNEA 
{ 
  TTLSKeyringParms 
  { 
    Keyring                   START2/TN3270 
  }   
} 

The keyring will be START2/TN3270 and Trace is not specified.

If you use Unix command pasearch -t , it will show keyring:START2/TN3270 and no trace statement in that section. Definitions with the same name are replaced, not merged.

Having just one TTLSCONFIG file makes it harder to manage. I would like to be able to have a configuration file for each port, or have all of the TLSRULEs in one file, and TTLSCipherParms in another file, and so on. It would make it easier to manager, and perform change management on the files.

The configurations from tcpImage TCPIP2 and tcpImage TCPIP2 are isolated from each other. If you want to use common definitions between tcpImages, put them in CommonTTLSConfig file.

The commonTTLSConfig statements are processed before the tcpImage statements, so a definition set in the tcpImage file will take precedence over a common definition.

The commonTTLSConfig file seems to need to be self consistent. I added

TTLSEnvironmentAction                 TNEA 
{ 
  TTLSSignatureParmsRef       TNESigParms 
} 

Without the TNESigParms definition. I got strange configuration error messages until I included the TNESigParms {..} in the file.

Using smaller units.

I remember some advice I was given… try to get all of your changes visible on one screen. Use subroutines or other ways of dividing up the code.

You can have

TTLSCipherParms 
{
   TTLSCipherParms 
   { 
      V3CipherSuites      TLS_CHACHA20_POLY1305_SHA256 
   } 
}

But the list of cipher suites could be long.

You can have a …REFerence o a set of definitions.

TTLSConnectionAction   TNCA 
{ 
  TTLSCipherParmsRef   TLS13TLS12 
} 
TTLSCipherParms        TLS13TLS12 
{ 
  #TLS 1.3 
   V3CipherSuites      TLS_CHACHA20_POLY1305_SHA256 
   #V3CipherSuites      TLS_AES_256_GCM_SHA384 
   #V3CipherSuites      TLS_AES_128_GCM_SHA256 
 #TLS 1.2 
   # NSTECC 
   V3CipherSuites   TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
   #RSA 
   V3CipherSuites      TLS_RSA_WITH_AES_256_CBC_SHA256 
} 

The allows you to create a “subroutine” out of the cipherspecs. It also allows you to use the same definitions in multiple places.

Within a TCPIPIMAGE configuration

The same parameter can be specified in more than one configuration statement. The documentation says:

For parameters that can be specified in multiple action types, the value used by a connection is
determined by the following hierarchical rule set, they first found is used
.

  1. If the parameter is specified in the TTLSConnectionAction statement that is the value used.
  2. If the parameter is specified in the TTLSEnvironmentAction statement that is the value used.
  3. If the parameter is specified in the TTLSGroupAction statement that is the value used.
  4. If a default value is defined, that is the value used.
  5. No value is used by AT-TLS and no parameter is explicitly passed to System SSL.

So if you have

TTLSEnvironmentAction  TNEA 
{ 
  TTLSCipherParmsRef     TLS13 
} 
TTLSConnectionAction   TNCA 
{ 
  TTLSCipherParmsRef    TLS13TLS12 
} 

The the CipherParms TLS13TLS12 will be used, because Connection is used before Environment.

If you use pasearch -t … it will display the configuration with sections like

TTLS Action:                  TNGA 
    Scope:                      Group 

TTLS Action:                  TNEA 
  Scope:                      Environment 

  TTLSCipherParms: 
    v3CipherSuites: 
      1303  TLS_CHACHA20_POLY1305_SHA256 
 ... 
TTLS Action:                  TNCA 
    Scope:                      Connection 
    TTLSCipherParms: 
     v3CipherSuites: 
      1303  TLS_CHACHA20_POLY1305_SHA256 
      C02C  TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 
      003D  TLS_RSA_WITH_AES_256_CBC_SHA256 

Because of the order, Scope:Connection takes precedence over Scope:Environment, the three cipher specs will be used.

When configuring AT-TLS I found it easiest if I used the Unix commands pasearch -t -f TN 1>a; oedit a and specify the rule name I was interested in (TN), then search for the last instance of the attribute of interest

PDSE or Unix file?

If you configuration is in Unix files, then you can get AT-TLS to reread this on regular basis – typically half an hour. This is useful of you want changes to be picked up automatically, but not if you want strict change control management.

AT-TLS configuration for TN3270

Below is the AT-TLS configuration for my telnet (PAGENTTN…) configuration.

TTLSRule                      TN 
{ 
  LocalPortRange              2023 
  Jobname                     TN3270 
  Direction                   INBOUND 
  TTLSConnectionActionRef     TNCA   
  TTLSGroupActionRef          TNGA 
  TTLSEnvironmentActionRef    TNEA 

} 
TTLSConnectionAction              TNCA 
{ 
  TTLSCipherParmsRef              TLS13TLS12 
  TTLSSignatureParmsRef           TNESigParms 
  TTLSConnectionAdvancedParmsRef  TNCOonAdvParms 
  CtraceClearText                 Off 
  Trace                           50 
} 
TTLSConnectionAdvancedParms       TNCOonAdvParms 
{ 
 ServerCertificateLabel  NISTECC521 
 ServerCertificateLabel  RSA2048 
#ccp this was added 
  ApplicationControlled         On 
  SSLv3          OFF 
  TLSv1          OFF 
  TLSv1.1        OFF 
  TLSv1.2        ON 
  TLSv1.3        OFF 
  SecondaryMap   OFF 
  HandshakeTimeout 3 
} 

TTLSGroupAction      TNGA 
{ 
  TTLSEnabled        ON 
  trace              50 
} 
TTLSKeyringParms    TNKEYRING 
{ 
  Keyring           START1/TN3270 
} 

TTLSEnvironmentAction      TNEA 
{ 
  HandshakeRole            Server 
  TTLSKeyringParms 
  { 
    Keyring                START1/TN3270 
  } 
  TTLSSignatureParmsRef    TNESigParms 
} 
TTLSSignatureParms         TNESigParms 
{ 
   CLientECurves Any 
} 
TTLSCipherParms             TLS13TLS12 
{ 
#TLS 1.3 
 V3CipherSuites      TLS_CHACHA20_POLY1305_SHA256 
#V3CipherSuites      TLS_AES_256_GCM_SHA384 
#V3CipherSuites      TLS_AES_128_GCM_SHA256 
#TLS 1.2 
# NSTECC 
 V3CipherSuites      TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 
#RSA 
 V3CipherSuites      TLS_RSA_WITH_AES_256_CBC_SHA256 
} 

I did many system SSL traces to get it working.

Using certificates

  • If you do not specify a certificate label in the configuration, AT-TLS takes the default from the keyring.
  • You can specify a certificate label using CertificateLabel…
  • If you want to specify more than one Certificate label – for example you are migrating from one certificate to another, or you want to support an RSA certificate and an Elliptic Curve certificate then specify one or more ServerCertificateLabel … statements.

Some lessons learned

  • When configuring TN3270 use V3CipherSuites not V3CipherSuites4char. V3CipherSuites takes 2 character identifiers and long TLS_… strings. V3CipherSuites4char only take 4 character identifiers , and not TLS_… strings.
  • If you change the PAGENT configuration you need F PAGNET,UPDATE to pick up the changes.
  • If you make a change to the PAGENT configuration, it does not always report problems. You should use Unix command commands like pagent -t -f TN 1>a ;oedit a to display the TTLS configuration for rule TN, and edit the file to check.
  • If you change a keyring, you need F CPAGENT,REFRESH to pick up the change.
  • When you start PAGENT use the -l /var/log/pagent.log -d1 options. Review the /var/log/pagent.log file and check for “WARNING” and “ERR”
  • The PAGENT configuration can have the same parameter specified at the environment level and at the connection level. The pasearch -t -f TN command displays both sets of data … you have to be careful you are checking the right set of data.
  • PAGENT does not report if a section was skipped. I had two TTLSConfig statements in a TCPIP image file, and only the last one was used.
  • You need the syslogd daemon running to capture error messages in a file.

General PAGENT commands

See here for starting PAGENT (and the trace levels you can use).

Updating PAGENT

If you change the PAGENT configuration (my job is CPAGENT) you can use

F CPAGENT,UPDATE

To refresh the configuration,

F CPAGENT,REFRESH

to refresh the configuration and restart processing. Existing sessions will continue unchanged.

When configuring TN3270 you can use the Unix command pasearch -t -f TN 1>a to display just the TLS policy you are interested in (TN) .

Displaying information

You display configuration information using the Unix command pasearch…

What does a rule configuration look like?

I frequently use

pasearch -t -f TN

This shows me the TLS configuration for rule TN

What does the high level TLS object look like?

pasearch -c -t

gave me

TTLS Policy Object:                                                     
  ConfigLocation:       Local             LDAPServer:        False      
  CommonFileName:                                                       
  ImageFileName:        //'USER.Z24C.TCPPARMS(PAGENTTN)'                
  ApplyFlush:           True              PolicyFlush:       True       
  ApplyPurge:           True              PurgePolicies:     True       
  AtomicParse:          True              DeleteOnNoflush:   False      
  DummyOnEmptyPolicy:   True              ModifyOnIDChange:  False      
  Configured:           True              UpdateInterval:    1800       
  TTLS Enabled:         True                                            
  InstanceId:           1666079380                                      
  LastPolicyChanged:    Tue Oct 18 08:49:40 2022                        

The CommonFileName: value was blank, which was a surprise as I had specified a file.

How to display a summary of a rule?

pasearch -t -n

gave

policyRule:             TN         
  TTLS Action:          TNGA       
  TTLS Action:          TNEA       
  TTLS Action:          TNCA       

How do I display which policy or rule has been used?

I could not find a way of displaying which rules were used, and which options were used.

Using Telnet (TN3270) on z/OS

This article gives some of the lessons I learned from using TN3270. My mission had been to connect x3270 to TN3270 (telnet) using TLS. Some things are obvious once you know, but frustrating all the same.

Creating the configuration

You start TN3270 with the name of the configuration file it should use. For me this was USER.Z24C.TCPPARMS(TN3270).

My file looks like

TelnetGlobals 
....
EndTelnetGlobals 

 include adcd.z24c.tcpparms(port0023)  ; General Applications 
 include user.z24c.tcpparms(tnpt2023)  ; TLS Support AT-TLS 
 include user.z24c.tcpparms(tnpt3023)  ; TLS Support AT-TLS 
                                                                

Where the include files contain self contained information about each port. My member name tnpo2023 is for TelNet, POrt 2023.

Restricting access

You can restrict which IP addresses can use which profile (port). See Transport Layer Security-Telnet profile example. The example below has a few minor tweaks from me.

TelnetParms         ; ATTLS defined secure port 
 TTLSPort 3023      ; 
 DEBUG CONN DETAIL JOBLOG 
 DEBUG CONN trace  CTRACE 
 ConnType None      ; Default is no access
EndTelnetParms 


BEGINVTAM
 Port 1023
 ...                    ; Mapping statements
 IPGROUP LocalIP        ; Subnets for buildings A and B
   255.255.255.0:10.1.1.0
   255.255.255.0:10.1.2.0
 ENDIPGROUP
 
 PARMSMAP BasicPG localIP  ; hosts defined in IPGROUP localIP 
 PARMSGROUP BasicPG     ; override default ConnType
   CONNTYPE NONE        ; support basic connections if mapped to this group
 ENDPARMSGROUP
; this defines who has access 
 PARMSMAP AdminPG 10.1.0.2 ; this ip address can use secure connections
 PARMSGROUP AdminPG     ; override default ConnType
   CONNTYPE SECURE      ; allow any type of connections if mapped to this group
 ENDPARMSGROUP
 
ENDVTAM

This says

  • The default connection type is NONE (from TelnetParms)
  • IP addresses 10.1.1.0, and 10.1.2.0 have PARMSMAP BASICPG which have CONNTYPE NONE.
  • IP address 10.1.0.2 has PARMSMAP AdminPG which has CONNTYPE SECURE.

Changing the configuration

You can update the TN3270 configuration while it is active. You use a command like

v tcpip,tn3270,obeyfile,USER.Z24C.TCPPARMS(TN3270)

Where USER.Z24C.TCPPARMS(TN3270) is the configuration file used at start up. If you have the configuration spread across several files, you cannot use OBEYFILE on one file – you need to use a complete configuration file. It appears to replace the current configuration with the specified one.

Displaying information.

You can use TSO netstat telnet to display the ports in use by Telnet. For proper display, you need to use the d tcpip,tn3270,…. command.

This is a bit restrictive as it only displays the information on the syslog. You can use Extended consoles, and so REXX can capture the output – but it still writes many records to SYSLOG and the operator console.

Display connection information

You can use the d tcpip,tn3270,conn,detail command, for example

EZZ6064I TN3270 CONN DISPLAY         FRAME LAST   F      E   SYS=S0W1
         ENCR                                           TSP          
CONN     TYPE IPADDR..PORT           LUNAME   APPLID    PTR LOGMODE  
-------- ---- ---------------------- -------- --------  --- --------       
00000048      10.1.0.2..51928        TCP00001 A06TSO02  TAE SNX32703       
----- PORT:    23  ACTIVE           PROF: CURR CONNS:      1               
------------------------------------------------------------               
00000043 C02F 10.1.0.2..48126        TLS00001           TPE                
00000046 C02F 10.1.0.2..40978        TLS00002 A06TSO03  TAE SNX32703       
----- PORT:  2023  ACTIVE           PROF: CURR CONNS:      2               
------------------------------------------------------------                     

Shows message EZZ6064I

  • there are two sessions with PORT 2023. Both using cipher suite C02F. The cipher spec value is described here.
  • The LUNAME of TCP… this comes from the BEGINVTAM .. part of the TN320 definitions.
  • Two terminals are connected to TSO (A06TS002), with the given logmode. The A in TSP means Active

EZZ… messages are here.

I could not see a way of displaying which z/OS certificate is being used.

Display profile information

d tcpip,tn3270,profile

gives

  PERSIS   FUNCTION        DIA  SECURITY    TIMERS   MISC        
 (LMTGCAK)(OPATSKTQSSHRTL)(DRF)(PCKLECXN23)(IPKPSTS)(SMLT)       
  -------  --------------  ---  ----------  -------  ----        
  L******  ***TSBTQ***RT*  TT*  BB********  IP**ST*  SMD*        
----- PORT:    23  ACTIVE           PROF: CURR CONNS:      0     
------------------------------------------------------------     
  L******  ***TSBTQ***RT*  TJ*  TSTTTT**TT  IP**STT  SMD*        
----- PORT:  2023  ACTIVE           PROF: CURR CONNS:      0     
------------------------------------------------------------     
  L******  ***TSBTQ***RT*  TJ*  TSTTTT**TT  IP**STT  SMD*        
----- PORT:  3023  ACTIVE           PROF: CURR CONNS:      1     
------------------------------------------------------------     
   FORMAT            LONG                                        
   NOSMFPROFILE                                                  
   TCPIPJOBNAME      TCPIP                                       
   TNSACONFIG        DISABLED                                    
   DEBUG TASK        EXCEPTION  CONSOLE                          
   DEBUG CONFIG      EXCEPTION  CONSOLE                          
   DEBUG CONFIG      TRACEOFF                                    
21 OF 21 RECORDS DISPLAYED                                       

If you issue d tcpip,tn3270,profile,detail you get a lot of output – it will display only the first nnn lines. You can change this value by d tcpip,tn3270,profile,detail,MAX=200.

You may find it easier to specify a port tcpip,tn3270,profile,port=23,detail to get less output.

To display the TN3270 configuration options you can specify profile=…

d tcpip,tn3270,profile,port=3023,profile=xxxx,detail

Where profile=xxxx can be PROFile =CURRent|prfid|ACTive|ALL|Basic|Pending|Secure

Current, Active, ALL and basic seem to display the same information. I do not know the difference between them.

Displaying “VTAM” information

You can display some of the configuration, but not all of it. For example

D TCPIP,TN3270,object,PORT=3023,type=parmsgrp

gives

OBJECT      CONNS  CLIENT ID CLIENT ID        ITEM                    
NAME        USING  TYPE      NAME             SPECIFIC   OPTIONS      
----------  ------ --------- ---------------- ---------- --------     
PARMSGRP                                                              
 BASICPG         0 IPGRP     LOCALIP   
 ADMINPG         1 IPADDR    10.1.0.2                                 

But you cannot display what LOCALIP is.

Where does the parameter come from?

d tcpip,tn3270,profile,port=3023,detail

This command gives

EZZ6080I TN3270 PROFILE DISPLAY 771                                          
  PERSIS   FUNCTION        DIA  SECURITY    TIMERS   MISC                    
 (LMTGCAK)(OPATSKTQSSHRTL)(DRF)(PCKLECXN23)(IPKPSTS)(SMLT)                   
  -------  --------------  ---  ----------  -------  ----                    
  *******  ***TSBTQ***RT*  EC*  BB********  *P**STS  *DD* *DEFAULT           
  L------  ------------T   TT-  ----------  I---ST-  SM-- *TGLOBAL           
  -------  -------------   TJ-  TSTTTT--TT  ------T  ---- *TPARMS            
  L******  ***TSBTQ***RT*  TJ*  TSTTTT**TT  IP**STT  SMD* CURR               

The field column headings are described here.

  • * means the option was turned off
  • – the option was not set.

In the first column (LMTGCAK)

  • The default is *
  • From the T(elnet)GLOBAL the value is L
  • From T(elnet)PARMS nothing is specified
  • So the Current definition is L

Quiescing and resuming ports

Quiescing a port stops new connections from using it. Resume allows it to be used.

v tcpip,tn3270,quiesce,port=3023
v tcpip,tn3270,resume,port=3023

Stopping a port may be bad for you

You can use a command

v tcpip,tn3270,stop,port=3023

Which cancels existing sessions using the port, and stops new connections from using it.

I cannot find how to start the port.

If you use

v tcpip,tn3270,obeyfile,USER.Z24C.TCPPARMS(TN3270)

to refresh the whole configuration all ports are restarted, so you can start all – but not just one port.

Setting up sftp on z/OS with ADCD

SFTP is an FTP implementation from openssl, it copies files to and from Unix Services.

The documentation z/OS OpenSSH User’s Guide(SC27-6806-50) is very good. It is clear, and answered most of my questions.

The ADCD implementation is not 100% complete, but it does not take much to fix it.

Background

The server runs in Unix Services. When you use “START SSHD”, it runs the started task SSHD which attaches a process in Unix Services, and then the started task ends! If you use the operator command “D A,SSH*” it will show it is running in Unix Services.

The documentation has several ways of stopping it – I just use cancel!

Messages are written to the syslog daemon.

It uses port 22. ADCD.Z24C.TCPPARMS(PROF2) has the statement

PORT                                                                 
    ...                         
    22 TCP SSHD*               ; port for sshd daemonrver            

This means that jobs SSHD* are authorised to use port 22.

Getting it working

Configure syslogd

See Setting up syslogd on z/OS.

To capture messages produced by SSHD, you need syslogd configured for SSHD. For example add to /etc/syslog.conf

*.SSHD.*.* /var/log/SSHD

Generate the missing certificates

From IBMUSER in OMVS, I issued

/usr/sbin/sshd -f /etc/ssh/sshd_config

This reported two cipher specs were missing. I used the command

ssh-keygen -A

This gave me

ssh-keygen: generating new host keys: ECDSA ED25519

Starting the sshd server

Use the operator command D A,SSH* to see if it is already running. if you want to restart it, cancel it using the operator command C SSHD…

Issue the operator command start SSHD. The started task will start, and then end, but will leave a Unix Services task running.

Note: After IPL, D SSH* gives

SSHD     SSHD     *OMVSEX  OWT  SO  A=0042   PER=NO   SMC=000 
                                    WUID=STC03715 USERID=START1       
                                    WKL=STARTED  SCL=STCLOM   P=1    
                                    

after SSHD is cancelled and restarted the output is

SSHD3    STEP1    START1   OWT  AO  A=0034   PER=NO   SMC=000       
                                    WUID=STC03701 USERID=START1      
                                    WKL=SERVERS  SCL=SRVOMVS  P=1    
                                    

so its workload behaviour may be different.

Use it

From my Linux machine I was able to use sftp colin@10.1.1.2 .

What is a link-local address and a global address in TCPIP V6?

When reading about routing in IP V6 there is frequent use of the terms link-local and global address. There are several definitions of what these mean – but I think you need to be an expert to understand them. Below are my definitions – they may be right – they may be wrong – but I hope they provide some useful information.

I found this site was a good basic guide to IP addresses.

Some basic information

  • A connection can either support IP V4 or IP V6 configuration
  • Each end of a connection has at least one IP address
  • IP addresses are hierarchical
    • The top 48 bits are global routing
      • If the top value is FE80 then the address is local. A router will not pass this outside.
      • If the top value is 2 then this is a global and the “ISP provider” is within the 48 bits. My Laptop has an IP V6 address like 2a00:1234:5678:9ABC. I used this site to display who my service provider was.
    • The next 16 bits are the subnet
    • The last 64 are the interface id
  • With IP V4, addresses starting 192.168 are local addresses and do not pass through a router – so FE80::… is not that new a concept.
  • A server needs fixed IP address, so clients can access it.
  • A client does not need a fixed IP address, as when it requests a service from the server, it sends its address as part of TCPIP. The server sends the reply back to this address.

The link local address

The link-local address at the end of a connection can have its address allocated:

  • Manually. This means you can give the IP address to your end users (or a DNS)
  • Allocated automatically. This can be based on the MAC address. IP V6 has network and neighbourhood discovery. As a connection becomes active it knows the IP address of the remote end, and can ask the remote end for the configuration it knows about. When the connection is closed, the network forgets the information about the connection, and its neighbourhood. The next time the connection starts, if it has a different IP address makes no difference – the information about the previous IP address has been forgotten
  • The advantage of having a different IP address is it obscures the client’s origin. If you have the same address each time, it is possible to build up a profile of your usage. If you use a different IP address – it makes it harder to do this.

If you have multiple network connections, you may need to help TCPIP send the traffic to the correct destination. For example

ping6 -I tap2 ….

which says sent it down the tap2 interface.

If you use ADCD the find_IO command gives

 FIND_IO for "colin@colin-ThinkCentre-M920s" 
                                                                                                
         Interface IPv4    IPv6           
 Path    Name      Address Address        
------   --------- ---------------------- 
 . 
  A0     tap0     10.1.1.1 fe80::d442:b0ff:fe0c:96ab%tap0  
  A1     tap1     10.1.2.1 fe80::a015:53ff:fe0b:8685%tap1  
d

With FTP

ftp fe80::7:7:7:7%tap1

GSK trace and TCPIP

To track down a TLS setup problem with TN3270 and AT-TLS, I had to collect a System SSL Trace. You can collect data and have it output to the joblog, or the console. This is not good practice as it can produce a lot of output, and it is hard to read the data.

This blog post follows on from Collecting a TCPIP Packet trace on z/OS.

You can use the same CTRACE writer procedure for all your CTRACE work. It is better not to have more than one trace writing to it at a time.

Erik Janssen sent me an email on how to take the CTRACE file and process it in Wireshark. I’ve put his comments at the bottom.

You need to start the GSK Server task

See SSL Server task

My GSKSRVR JCL looks like

//GSKSRVR  PROC  REGSIZE=256M,OUTCLASS='A' 
//*-------------------------------------------------------------------- 
//GO       EXEC  PGM=GSKSRVR,REGION=&REGSIZE,TIME=1440, 
//  PARM=('ENVAR("HOME=/etc/gskssl/server"),TERM(DUMP)                 X
//             / 1>DD:STDOUT 2>DD:STDERR') 
//STDOUT   DD  SYSOUT=&OUTCLASS,DCB=LRECL=250, 
//  FREE=END,SPIN=UNALLOC 
//STDERR   DD  SYSOUT=&OUTCLASS,DCB=LRECL=250, 
//  FREE=END,SPIN=UNALLOC 
//SYSOUT   DD  SYSOUT=&OUTCLASS, 
//  FREE=END,SPIN=UNALLOC 
//CEEDUMP  DD  SYSOUT=&OUTCLASS, 
//  FREE=END,SPIN=UNALLOC 

I did not change any parameters, or defaults.

Start it

s GSKSRVR

It gives

GSK01001I System SSL version 4.4, Service level OA59115.
GSK01003I SSL server initialization complete.

Within the TELNET (TN3270) parameters I had

TelnetParms         ; ATTLS defined secure port 
 TTLSPort 2023      ; 
 DEBUG CONN DETAIL CTRACE 
 DEBUG CONN trace  CTRACE 
 DEBUG TRACE CTRACE
 ConnType Secure    ; Client chooses secure or nonsecure connection. 
EndTelnetParms 

This limits the trace to only port 2023, other ports, such as 0023 were unaffected.

I set up parmlib member for GSK trace, member CPGSKON

TRACEOPTS 
          WTRSTART(ctwtr) 
          on 
          jobname(TCPIP) 
          wtr(ctwtr) 
          OPTIONS('LEVEL=255') 

I turned trace on using

TRACE CT,ON,COMP=GSKSRVR,PARM=CTGSKON

This gave

IEE252I MEMBER CTGSKON FOUND IN USER.Z24C.PARMLIB
GSK01040I SSL component trace started.
ITT038I ALL OF THE TRANSACTIONS REQUESTED VIA THE TRACE CT COMMAND WERE SUCCESSFULLY EXECUTED.

ITT110I INITIALIZATION OF CTRACE WRITER CTWTR COMPLETE.

The CTWTR procedure was started was part of this command.

You stop the trace with

trace CT,off,COMP=GSKSRVR

Wait for the message

ITT038I ALL OF THE TRANSACTIONS REQUESTED VIA THE TRACE CT COMMAND WERE SUCCESSFULLY EXECUTED.

And stop the CTWTR writer using

TRACE CT,WTRSTOP=CTWTR

You should get messages

ITT038I ALL OF THE TRANSACTIONS REQUESTED VIA THE TRACE CT COMMAND WERE SUCCESSFULLY EXECUTED.
IEE839I ST=(ON,0001M,00005M) AS=ON BR=OFF EX=ON MO=OFF MT=(ON,064K)
IEF196I AHL904I THE FOLLOWING TRACE DATASETS CONTAIN TRACE DATA :
IEF196I IBMUSER.CTRACE1
AHL904I THE FOLLOWING TRACE DATASETS CONTAIN TRACE DATA :
IBMUSER.CTRACE1

ITT111I CTRACE WRITER CTWTR TERMINATED BECAUSE OF A WTRSTOP REQUEST.

If there is data in the file, you can use IPCS to format it.

The IPCS command is

CTRACE COMP(GSKSRVR) FULL ALL

You get output like

S0W1      MESSAGE   00000008  15:19:52.221020  SSL_INFO                 
  Job TCPIP     Process 0201003E  Thread 00000001  read_v3_client_hello 
  Received CLIENT-HELLO message                                         
                                                                        
S0W1      DUMP      00000020  15:19:52.221414  SSL_ASCII_DUMP           
  Job TCPIP     Process 0201003E  Thread 00000001  read_v3_client_hello 
  CLIENT-HELLO message                                                  
    00000000: 010001FC 03030C33 81E156C3 DF4693DD   *.......3..V..F..*  
    00000010: 621CA636 8A75BDF0 26F3DE8F 831B78BC   *b..6.u..&.....x.*
...
S0W1      MESSAGE   00000008  15:19:52.226897  SSL_INFO                  
  Job TCPIP     Process 0201003E  Thread 00000001  edit_ciphers          
  Using server certificate 'ZZZZ'                                        
...
S0W1      MESSAGE   00000008  15:19:52.223132  SSL_INFO                         
  Job TCPIP     Process 0201003E  Thread 00000001  read_v3_extended_client_hello
  Elliptical curve 0030 is being skipped as it is only supported in TLS 1.3     

Getting the data into Wireshark format.

Wireshark is an excellent tool for doing network trace, and decoding the flows. You can also is it to process the CTRACE data. Thanks for Eril Janssen for the instructions below on how to get from CTRACE to Wireshark.

You need to use the CTRACE SNIFFER option. This writes to the file with DDNAME of SNIFFER

Allocate a VB 1600 LRECL dataset and allocate it to a ddname, for example SNIFFER
ALLOC DD(SNIFFER) DS(<some dsname>) SHR
From IPCS you can now:
CTRACE COMP(SYSTCPDA) GMT SHORT
OPTIONS((SNIFFER(1600,TCPDUMP) NOREASSEMBLY))
DS(‘<the trace ds>’)
The formatted trace will now be in <some dsname>. Do a binary transfer to your pc and you show be able to open the trace in wireshark.

I tend to use IPCS in batch (so I do not get the lock on the trace file, (grin)).

Problems

I was using CTRACE, the IPCS, then CTRACE etc. Sometimes the CTRACE writer would not start (or stop). This can be because you are still in IPCS, and IPCS has a lock on the dataset, or you have quit from IPCS, and TSO still has a lock on the data set. I used =X to get out of the ISPF session, and this usually freed it up.

I could it was easiest to run IPCS in batch – it saved lots of typing, and starting/stopping CTRACE when I had got it wrong.

There may still be a timing window, where the trace writer would not stop. When I stopped gsksrvr, the trace writer stopped.

Configuring TCPIP on z/OS is as easy as — um.

When I was young I was told that if you cannot say something good about anyone, then do not say anything; or to put it another way; focus on the positive and not the negative. Here goes…

Configuring TCPIP on z/OS

In general, some of the requirements for making changes include:

  • Being able to undo or back-out a change
  • Make the smallest change necessary
  • Changes should be simple to implement
  • Have changes being worked on in parallel
  • You implement the same change in production that was tested in earlier stages, so no typing.
  • Only authorised people are allowed to make changes.

What is good about TCPIP configuration

  • When I configured my first TCPIP system, I thought that it was easy to configure. Since then, working with more complex changes, my views have changed.
  • You can use system symbols, so you can have one configuration across many systems, and exploit symbols like SYSNAME=MVS1, or SYSNAME=MVS2. Of course where there are multiple instances of &SYSNAME – they all get the same value, which makes it even easier to configure!

How does it work

In the TCPIP procedure JCL are statements like

//SYSTCPD DSN=ADCD.Z25A.TCPPARMS(TCPDATA),DISP=SHR 
//PROFILE DISP=SHR,DSN=ADCD.Z25A.TCPPARMS(PROF2) 

SYSTCPD is used by clients or servers. This has information about how to use TCPIP: (including which TCPIP, if there is more than one).

DOMAINORIGIN  DAL-EBIS.IHOST.COM     
TCPIPJOBNAME TCPIP     
DATASETPREFIX TCPIP     

PROFILE is used to configure the links, connections etc of the TCPIP address space. The remainder of the post is about configuring this dataset.

In the profile you can define:

  • IP V4 route statements
  • IP V6 route statements
  • Which hardware connections to use, and what IP addresses these have.
  • Reserved ports
  • Startup trace configuration.

Conceptually this profile is one large file, but you can use includes such as

include adcd.Z25A.tcpparms(zconnect)

to include specific files or members. But you cannot have

BEGINRoutes 
include user.Z25A.tcpparms(routeinc) 
ENDRoutes 

because each major statement has to be totally within one file.

Operator commands to change the configuration

As well as the profile you can alter the configuration by using the operator command, such as

v tcpip,,syntax,user.z25a.tcpparms(iface6)
v tcpip,,obey,user.z25a.tcpparms(iface6)

The syntax command checks the syntax of the statements, and allows you to fix any syntax problems before you use the OBEY command.

Note: The syntax check does not check for consistency or pre requirements. I had a request which passed the syntax check but failed because a VTAM resource was not present.

You can have include files like

 INTERFACE IFPORTCP6  DELETE 
 INTERFACE IFPORTCP6 
   DEFINE IPAQENET6 
   CHPIDTYPE OSD 
   PORTNAME PORTCP 
   INTFID 7:7:7:7 
                                                                          
 BEGINRoutes 
 ; Destination      SubnetMask    FirstHop LinkName    Size 
 ROUTE 172.25.1.0   255.255.255.0  =       IFPORTCP    MTU 1492 
 ROUTE DEFAULT      172.25.1.6             IFPORTCP    MTU 1492 
 ROUTE 2a00::/64                           IFPORTCP6   MTU 1 
 ENDRoutes 
 START IFPORTCP6 

This is typical of the documentation, as it is a nice self contained example. It:

  • deletes an interface
  • defines an interface
  • defines some routes – how to route packets to different systems
  • starts the interface

This is OK for a simple, one user, type of system.

You can use commands like

v tcpip,,start…
v tcpip,,stop...

to manage resources.

The command syntax is a bit strange, rather than v tcpip,start…, or v tcpipprd,start.. you have to specify v tcpip,tcpipprd,start – passing the name of the TCPIP job as the second parameter.

Change control

Simplistic change control

You can change the file, and restart TCPIP to pick up the changes.

Better change control

To make a change

If you put sections in a file or member, you can change the member and use obeyfile command on the file. For example have a file called user.tcpip(route1)

  BEGINRoutes 
  ; Destination        SubnetMask    FirstHop   LinkName    Size 
    ROUTE 172.25.1.0     255.255.255.0    =       IFPORTCP    MTU 1492 
    ROUTE DEFAULT6       fe00::                     IFPORTCP6   MTU 1492 
  ENDRoutes

To make a change, (to replace all the static routes)

  • you copy this to user.tcpip.old(route1).
  • make the change
  • use v tcpip,,syntax,user.tcpip(route1)
  • use v tcpip,,obey,user.tcpip(route1)

If it does not work, you use obey,user.tcpip.old(route1) to undo the change, and then fix the problem.

Two stage changes

Some changes need a delete followed by a define. There is no define replace.

If you have a delete… define… in one file, this may fail because the delete is asynchronous, and the operation is ongoing after the delete command has finished. The define then fails because the object still exists.

The best way of configuring seems to be:

  • Have the define statement in one file, which can be included in the TCPIP startup profile, or used in an OBEY command;
  • Have a file with the matching delete in a file which is used in an obey command
  • At startup the define file is used.
  • To modify it, use two commands, obeyfile… delete, obeyfile… define .

Production change control

Things you may need to consider when making changes:

  • There are often changes made in parallel, for example from different departments. Some of these changes can be made independently of each other. Others changes, like beginroutes… endroutes, need to be coordinated, and done serially.
  • If you are using system variables, for example a statement like
    • HOME &HOMEIPADDRESS1 ETH1,
  • you will need to define/change the symbol on each system and activate the resource.

Where you need to be careful.

The size of the change.

When you define static routes (between BEGINROUTES and ENDRoutes) if you want to change it, you replace all of the definitions; you cannot add or delete individual routes.

Unauthorised changes.

It seems that a userid which is authorised to issue the OBEY command, can issue the command against any file, so could use

VARY TCPIP,,OBEY,EVIL.PERSON.CONFIG(change) ,

and so someone can issue an an unauthorised change. With VTAM, an authorised operator, can only activate a member in a PDS – not use a random PDS member. You can control who can update datasets in the VTAMLST concatentation. This gives better protection.

To give a userid OBEYFILE access use RACF definitions

RDEFINE OPERCMDS MVS.VARY.TCPIP.OBEYFILE UACC(NONE)
PERMIT MVS.VARY.TCPIP.OBEYFILE ACCESS(CONTROL) CLASS(OPERCMDS) GROUP(CSYSPR)

This command seems to give authority to the obeyfile command in all address spaces, eg TCPIP, TCPIP1 etc.

I could not find a way of giving a userid permission on one TCPIP image, and no permission on another TCPIP image.

It is hard to make a small change

I wanted to make a small change to the reserved ports.

If this was VTAM, with JCL like

//VTAMLST DD DISP=SHR,DSN=USER.Z25A.VTAMLST
//        DD DISP=SHR,DSN=ADCD.Z25A.VTAMLST       

where my local customising is in USER.VTAMLST and the IBM provided customising is in ADCD.VTAMLST. To make a change, I add the entry to USER.VTAMLST. I do not change the IBM provided stuff. When I upgrade to a newer level, I use the updated version of ADCD.VTAMLST and my changes are still in USER.VTAMLST.

With the TCPIP approach, I have to change the IBM configuration, if only to point to my user.TCPPARMS file.

I had to update ADCD.TCPPARMS(PROF2). When a new level is available, I have to look at the dates, and compare the members, and reapply my changes! Not just a simple step.

If it had been me, I would have conditional includes so you would have

include USER.Z25A.TCPPARMS(ports) cond
include ADCD.Z25A.TCPPARMS(ports) required

where I put my configuration of TCPIP port numbers in the user…tcpparms(ports). If this member is not found, it produces a warning. When adcd…tcpparms(ports) is processed, it adds to my port definitions. If this file does not exist, and required is specified, then TCPIP does not start up.

Of course TCPIP configuration would also have to change to allow two or more BEGINROUTES…ENDROUTES sections.

Overall

Overall, the configuration is not too bad. I think VTAM configuration works well. Once you are used to the different syntax used by TCPIP commands, TCPIP is OK, but it does feel like extra typing! I would rather have “add route” and “delete route” instead of having to replace all of the static routes. It goes against the “minimum change” aspect of change control.

I do wonder why TCPIP did a completely different configuration interface to VTAM – but it will not change now.