Projekat

Općenito

Profil

Akcije

Podrška #13998

Zatvoren

IPTABLES Firewall Example - ocean

Dodano od Ernad Husremović prije oko 18 godina. Izmjenjeno prije više od 17 godina.

Status:
Zatvoreno
Prioritet:
Normalan
Odgovorna osoba:
Kategorija:
iptables
Početak:
17.04.2008
Završetak:
% završeno:

0%

Procjena vremena:

Opis

OCEAN PARK SOFTWARE CONSULTING
serving the Internet since 1992

IPTABLES Firewall Example

  1. Red Hat Linux firewall using iptables #
  2. Created: October 2002
  3. Last Revised: August 2006 #
  4. Authors: Dennis G. Allard () and Don Cohen () #
  5. This script works on on servers running Red Hat 7.3, 8.0, 9.0, and
  6. RHEL ES 3 and 4. Variants of this script are in active use on
  7. many servers. #
  8. No warranty is implied. Use at your own risk!!
  1. Using this script
  2. ----------------- #
  3. I save this file as /etc/sysconfig/iptables-precursor
  4. and then source it and run iptables-save to create
  5. /etc/sysconfig/iptables, which is an input file
  6. consumed by the script /etc/rc.d/init.d/iptables,
  7. which in turn makes use of the script /sbin/iptables-restore. #
  8. Before mucking with setting up iptables, you should
  9. disconnect the machine from the internet. Examine
  10. and understand the current set of iptables rules
  11. before you reconnect to the internet. #
  12. To configure the set of iptables rules: #
  13. /etc/rc.d/init.d/iptables stop
  14. source /etc/sysconfig/iptables-precursor #
  15. To save the current set of iptables rules for use at next reboot:
  16. iptables-save > /etc/sysconfig/iptables
  17. To dynamically restart iptables after modifying /etc/sysconfig/iptables: #
  18. /etc/rc.d/init.d/iptables restart #
  19. Note that /etc/rc.d/init.d/iptables is a script. You can read it to
  20. gain understanding of how iptables uses iptables-restore to restore
  21. iptables firewall rules at reboot. #
  22. To examine the current set of rules in effect: #
  23. /etc/rc.d/init.d/iptables status #
  24. However, I prefer to show the current set of rules via: #
  25. iptables -nvL -t filter
  26. iptables -nvL -t nat #
  27. or #
  28. iptables -vL -t filter
  29. iptables -vL -t nat # #
  30. To configure iptables to be used at next system reboot:
  31. chkconfig --add iptables #
  32. To see if iptables is currently configured to start at boot, do:
  33. chkconfig --list iptables #
  34. (You might have to do chkconfig --del ipchains to remove ipchains) #
  35. The rest of this file is derived from my old ipchains script. #
  1. A word about routing
  2. --------------------
  3. Note that this web page does not discuss routing decisions. Routing
  4. (see the 'ifconfig' and 'route' commands) decides which interface an
  5. incoming packet will be delivered to, i.e. if a given packet will be
  6. 'input' to this machine or be 'forwarded' to some interface for
  7. delivery to another machine, say on an internal network. You should
  8. have your routing configured before you attempt to configure your
  9. firewall. #
  10. Caveat. DNAT and SNAT provide a way for the IPTABLES firewall to modify the
  11. Destination or Source IP addresses of a packet and, in this way, interact
  12. with routing decisions. See section below: 'More about NAT and routing'. #
  1. The network
  2. ----------- #
  3. This firewall is running on a gateway machine having multiple ethernet
  4. interfaces, a public one, eth0, which is a DSL connection to an ISP,
  5. and one or more internal ones, including eth1, which is assigned to
  6. 192.168.0.1, an IP number on my internal private network. My public
  7. network has static IP numbers depicted below as x.y.z.... Actual
  8. IP numbers would, of course, be a sequence of four octets. For this
  9. script, I assume that the firewall is running on the same machine
  10. having the interfaces configued with my public IPs. For this reason,
  11. most of the rules below are INPUT rules. Were I to route some of my public
  12. static IP numbers to interfaces on one or more machines inside the
  13. firewall on the internal network, I would modify certain rules to be
  14. FORWARD rules instead of INPUT rules. I show some examples below of
  15. FORWARD rules. Finally, the script is just for a single server IP,
  16. hence all of the "/32" network masks below. A more realistic situation
  17. would involve using IP ranges and their corresponding network masks. #
  18. The gateway at my ISP is x.y.z.1. I run a few web servers on
  19. x.y.z.w, a DNS server on x.y.z.n, and qmail on x.y.z.m. #
  20. Using this file in a more complex network would require some
  21. modifications. Particular attention would need to be given to using
  22. the right the IP numbers and interfaces, among other things. :-) #
  1. Preliminaries
  2. ------------- #
  3. To permit machines internal to the network to be able to
  4. send IP packets to the outside world, enable IP Forwarding: #
  5. echo 1 > /proc/sys/net/ipv4/ip_forward #
  6. Prevent SYN floods from consuming memory resources: #
  7. echo 1 > /proc/sys/net/ipv4/tcp_syncookies #
  8. I place the above echo commands into /etc/rc.d/rc.local
  9. so that they will be executed at boot time. #
  1. The basic idea of this firewall
  2. ------------------------------- #
  3. Provide rules that are applied in the following order: #
  4. ACCEPT all UDP packets for certain UDP services #
  5. Currently the only UDP connections I accept are to my secure DNS
  6. server, tinydns. For an explanation of why tinydns is secure, see:
  7. http://www.faqts.com/knowledge_base/view.phtml/aid/8739/fid/699. #
  8. DENY all other UDP packets. #
  9. ACCEPT SYN packets just for certain TCP services #
  10. SYN packets are specified via the -syn flag in the input
  11. rules defined below. Note that certain services can be
  12. further filtered by xinetd. #
  13. DENY all other TCP SYN packets. #
  14. ACCEPT all other TCP packets that are part of existing connections #
  15. DENY all other TCP packets. #
  16. In other words, we allow any TCP packet through that is part of an
  17. established TCP connection, but we are very selective in just which
  18. connections we permit to be made to start off with. #
  19. A brief explanation of SYN packets goes as follows. TCP connections
  20. are initiated via a hand shaking protocol between the client and server
  21. programs at either end of the connection. The very first TCP packet
  22. is sent by the client to the server and is called a SYN packet,
  23. because it has the SYN flag set to 1 in the TCP packet header. We
  24. only allow SYN packets for the specific servers running on specific
  25. ports of specific hosts. Subsequently, we only permit further TCP
  26. packets in that are determined to be part of a connection whose
  27. initial SYN packet was already accepted and responded to by one of our
  28. servers. This is done via 'Stateful Packet Inspection' provided by the
  29. netfilter functionality added to linux as of kernel 2.4. By stopping all
  30. other packets in their tracks, we limit attempts to attack our internal
  31. network.
  32. There are subtle ways that Denial of Service attacks can be performed
  33. if an attacker is able to somehow gain access to a machine inside our
  34. network or otherwise hijack a connection. However, even in such
  35. cases, current research is leading to ways to greatly limit the effect
  36. of such attacks. For further reading, see: http://www.cs3-inc.com/ddos.html. #
  37. For detailed background reading about iptables, please refer to:
  38. http://www.netfilter.org/documentation/HOWTO/packet-filtering-HOWTO.html #
  1. begin oceanpark.com firewall rules (using iptables)
  2. ---------------------------------------------------
  1. Here we go...
#
  1. Configure default policies (-P), meaning default rule to apply if no
  2. more specific rule below is applicable. These rules apply if a more specific rule below
  3. is not applicable. Defaults are to DROP anything sent to firewall or internal
  4. network, permit anything going out. #
    iptables -P INPUT DROP
    iptables -P FORWARD DROP
    iptables -P OUTPUT ACCEPT
#
  1. Flush (-F) all specific rules #
    iptables -F INPUT
    iptables -F FORWARD
    iptables -F OUTPUT
    iptables -F -t nat
  1. The rest of this file contains specific rules that are applied in the order
  2. listed. If none applies, then the above policy rules are used.
#
  1. Forward all packets from eth1 (internal network) to eth0 (the internet). #
    iptables -A FORWARD -i eth1 -o eth0 -j ACCEPT
#
  1. Forward packets that are part of existing and related connections from eth0 to eth1. #
    iptables -A FORWARD -i eth0 -o eth1 -m state --state ESTABLISHED,RELATED -j ACCEPT
#
  1. Permit packets in to firewall itself that are part of existing and related connections. #
    iptables -A INPUT -i eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT
  1. Note, in the above two rules, a connection becomes ESTABLISHED in the
  2. iptables PREROUTING chain upon receipt of a SYNACK packet that is a
  3. response to a previously sent SYN packet. The SYNACK packet itself is
  4. considered to be part of the established connection, so no special
  5. rule is needed to allow the SYNACK packet itself.
#
  1. Allow all inputs to firewall from the internal network and local interfaces #
    iptables -A INPUT -i eth1 -s 0/0 -d 0/0 -j ACCEPT
    iptables -A INPUT -i lo -s 0/0 -d 0/0 -j ACCEPT
#
  1. Enable SNAT functionality on eth0 #
  2. SNAT (Source NAT) is used to map private source IP numbers of
  3. interfaces on the internal LAN to one of my public static IP numbers.
  4. SNAT performs this mapping when a client running on one of the
  5. internal hosts (x.y.z.c) initiates a TCP connection (SYN) through
  6. eth0. #
    iptables -A POSTROUTING -t nat -s 192.168.0.0/24 -o eth0 -j SNAT --to-source x.y.z.c
#
  1. Alternative to SNAT -- MASQUERADE #
  2. If your firewall has a dynamic IP number because it connects to the
  3. internet itself via DHCP, then you probably cannot predict what the IP
  4. number is of your firewall's interface connected to the internet. In
  5. this case, you need a rule like the following that assigns the (an) IP
  6. number associated with eth0 to outgoing connections without you needing
  7. to know in advance (at time of writing this rule) what that IP number is: #
  8. iptables -A POSTROUTING -t nat -o eth0 -j MASQUERADE #
  9. Note that the above SNAT and MASQUERADE rules are applicable
  10. independent of how a host on the internal network is assigned its own
  11. internal IP number. The host could be assigned a static IP number on
  12. an internal nonpublic network (e.g. 10. or 192.168.) or it could be
  13. itself assigned a dynamic IP number from your own DHCP server running
  14. on the firewall, or it could even have a public static IP number.
  15. However, it seems unlikely that one would want to assign a public IP
  16. number to a host and then proceed to hide that number from the public. #
#
  1. Deny any packet coming in on the public internet interface eth0
  2. which has a spoofed source address from our local networks: #
    iptables -A INPUT -i eth0 -s x.y.z.s/32 -j DROP
    iptables -A INPUT -i eth0 -s x.y.z.c/32 -j DROP
    iptables -A INPUT -i eth0 -s 192.168.0.0/24 -j DROP
    iptables -A INPUT -i eth0 -s 127.0.0.0/8 -j DROP
#
  1. Accept all tcp SYN packets for protocols SMTP, HTTP, HTTPS, and SSH:
  2. (SMTP connections are further audited by our SMTP server) #
    iptables -A INPUT -p tcp -s 0/0 -d x.y.z.m/32 --destination-port 25 --syn -j ACCEPT
    iptables -A INPUT -p tcp -s 0/0 -d 0/0 --destination-port 80 --syn -j ACCEPT
    iptables -A INPUT -p tcp -s 0/0 -d 0/0 --destination-port 443 --syn -j ACCEPT
    iptables -A INPUT -p tcp -s 0/0 -d 0/0 --destination-port 22 --syn -j ACCEPT
#
  1. Notice that the above rules are all INPUT rules. My current network
  2. does not require me to make use of FORWARD rules, since I run all
  3. publicly accessible servers directly on my firewall machine. But I
  4. promised above in the description of my network to give examples of
  5. rules used when there are servers running on machines on the internal
  6. network. Following are examples of FORWARD rules I would use if I ran
  7. mail, web, and ssh servers on machines on the internal network inside
  8. the firewall. #
  9. iptables -A FORWARD -p tcp -s 0/0 -d x.y.z.m/32 --destination-port 25 --syn -j ACCEPT
  10. iptables -A FORWARD -p tcp -s 0/0 -d x.y.z.w/32 --destination-port 80 --syn -j ACCEPT
  11. iptables -A FORWARD -p tcp -s 0/0 -d x.y.z.w/32 --destination-port 443 --syn -j ACCEPT
  12. iptables -A FORWARD -p tcp -s 0/0 -d 0/0 --destination-port 22 --syn -j ACCEPT #
  13. The first three of the above four rules would be used if my routing
  14. delivered packets having destination IP x.y.z.m, port 25, or IP
  15. x.y.z.w, port 80 or 443, to an interface connected to my internal
  16. network (i.e. the packet was being FORWARDed). The fourth of the above
  17. four rules is similar but operates on any destination IP, port 22.
  18. The difference between an INPUT rule and a FORWARD rule is that an
  19. INPUT rule applies to packets that are 'input' to this machine (the
  20. machine on which these iptables firewall rules are installed), whereas
  21. a FORWARD rule applies to packets that are being 'fowarded', i.e. to
  22. packets that are passing through this machine to some other machine,
  23. such as a machine on my internal network.
  24. If I ran my mail server on an internal machine, I would no longer
  25. need my previous INPUT rule for x.y.z.m and would use the above
  26. FORWARD rule instead. #
  1. Begin Caveat, More about NAT and routing
  2. The above talk of routing is independent of the rules defined here.
  3. I.e., routing is determined by ifconfig, route, et. al. I have not
  4. yet seen any very good explanation of how to setup the static routing
  5. table (what you see as output from the `route` command). I will not
  6. attempt to remedy that lacuna at this time. If you know of some
  7. good documenation that completely and accurately explains the
  8. semantics of the ifconfig and route commands, i.e., explains what
  9. affect each has such that I can reliably predict what the output
  10. of `route` will be after executing a sequence of ifconfig and
  11. route commands, then please do let me know.
  12. What can be done by IPTABLES rules that has the 'feel' of routing is
  13. DNAT (Destintion NAT) and SNAT (Source NAT). DNAT and SNAT rules are,
  14. respectively, mechnisms to map the incoming destination IP number and
  15. outgoing source IP number to different IP numbers. For example, SNAT
  16. can be used to map an internal source IP number to any one of your
  17. external public IP numbers so that a workstation on your internal
  18. network will appear to servers on the internet to which it connects to
  19. have a source IP number equal to the mapped public IP number.
  20. DNAT goes the other way. It is a mechanism used typically to map
  21. public destination IP numbers to internal private IP numbers. (In
  22. fact, DNAT could also map public to public or private to private or
  23. private to public, but that is left as an exercise for the reader).
  24. So, for example, if you run a mail server on a machine configured with
  25. an internal IP number but wish to expose that service to the external
  26. world via a public IP number, DNAT is for you.
  27. Now, DNAT and SNAT are not routing but can interact with routing.
  28. Routing decides whether a packet is going to be INPUT to this machine
  29. or be FORWARDed to another machine. That decision is done by routing.
  30. Once that decision is made, and only then, are the IPTABLES filtering
  31. rules (FORWARD and INPUT rules) applied to a given packet. On the
  32. other hand DNAT is applied by a PREROUTING rule and SNAT by a POSTROUTING
  33. rule. It is now time for you to read the following Packet Filtering
  34. HOWTO section:
  35. http://www.netfilter.org/documentation/HOWTO/packet-filtering-HOWTO-9.html
  36. which states:
  37. It's common to want to do Network Address Translation (see the
  38. NAT HOWTO) and packet filtering. The good news is that they mix
  39. extremely well. [editor- The NAT HOWTO can be found at:
  40. http://www.netfilter.org/documentation/HOWTO/NAT-HOWTO.html]
  41. You design your packet filtering completely ignoring any NAT you
  42. are doing. The sources and destinations seen by the packet filter
  43. will be the `real' sources and destinations. For example, if you
  44. are doing DNAT to send any connections to 1.2.3.4 port 80 through
  45. to 10.1.1.1 port 8080, the packet filter would see packets going
  46. to 10.1.1.1 port 8080 (the real destination), not 1.2.3.4 port 80.
  47. Similarly, you can ignore masquerading: packets will seem to come
  48. from their real internal IP addresses (say 10.1.1.1), and replies
  49. will seem to go back there.
  50. Hence, INPUT/FORWARD rules would operate on destination IP numbers
  51. after a DNAT rule is applied. But if you don't have any DNAT rules,
  52. then INPUT/FORWARD would apply to the IP numbers as they are in the
  53. incoming packet.
  54. INPUT or FORWARD would be needed purely depending on whether your
  55. routing would cause the packet to stay on the machine where the
  56. firewall is installed or be forwarded to another machine. THAT
  57. decision is done by routing and not by DNAT or SNAT or anything
  58. else in this firewall script.
  59. It is perfectly possible for the machine having the firewall to have
  60. both public and internal IPs configured and/or for some packets to be
  61. INPUT and others to be FORWARDed.
  62. DNAT is done by a PREROUTING rule, so you should think of things as
  63. proceeding in the following order:
  64. 1. apply PREROUTING DNAT rules (if any) to map destination IP
  65. 2. apply routing decisions (see ifconfig et. al.)
  66. 3a. apply INPUT rules to packets having a destination IP on this machine
  67. 3b. apply FORWARD rules to packets having a destination IP elsewhere
  68. 4. apply POSTROUTING SNAT rules (if any) to map source IP
  69. (3a and 3b can be done in either order since they apply to a mutually
  70. exclusive set of packets)
  71. I think that's correct.
  72. End Caveat, More about NAT and routing #
#
  1. Sometimes I run older versions of SSH on port 2200: #
    iptables -A INPUT -p tcp -s 0/0 -d 0/0 --destination-port 2200 --syn -j ACCEPT
#
  1. For imapd via stunnel (instead of xinetd-based imapd): #
    iptables -A INPUT -p tcp -s 0/0 -d 0/0 --destination-port 993 --syn -j ACCEPT
#
  1. For xinetd-based IMAP server (see /etc/xinetd.conf for who can use it): #
    #iptables -A INPUT -p tcp -s 0/0 -d 0/0 --destination-port 143 --syn -j ACCEPT
#
  1. For DHCP server: #
    iptables -A INPUT -i eth1 -p tcp --sport 68 --dport 67 -j ACCEPT
    iptables -A INPUT -i eth1 -p udp --sport 68 --dport 67 -j ACCEPT
#
  1. For LDAP clients: #
    #iptables A INPUT -p tcp -s 0/0 -d 0/0 --destination-port 389 -syn -j ACCEPT
    #dga
    worry about LDAP later (after I decode LDAP documentation (-;)
#
  1. DNS queries: #
  2. Permit responses from our ISP's DNS server. When a client running on our
  3. host makes a DNS query, the outgoing query is allowed since we permit all
  4. outgoing packets. The reply will be a UDP connection back to the high
  5. numbered client port from which the query was made. So we only need to
  6. permit UDP packets from our ISP's DNS servers back to high numbered ports: #
    #iptables -A INPUT -p udp -s <ISP DNS server IP>/32 --source-port 53 -d 0/0 --destination-port 1024:65535 -j ACCEPT #
  7. But since we trust our ISP DNS Server not not have been hacked and we may
  8. not be sure what our client IP range is, we loosen this to: #
    iptables -A INPUT -p udp -s <ISP DNS server IP>/32 --source-port 53 -d 0/0 -j ACCEPT
#
  1. Running a caching DNS Server #
  2. We need to permit querying a remote DNS server. Since I am running
  3. a caching DNS server on x.y.z.d that makes requests for DNS lookups
  4. to external DNS servers, those servers send back responses via UDP to
  5. the high numbered client port on x.y.z.d where the caching server listens.
  6. I could of course increase security by running the dns cache on its own
  7. machine/IP and restricting to just that machine/IP. #
    iptables -A INPUT -p udp -s 0/0 --source-port 53 -d x.y.z.d/32 --destination-port 1024:65535 -j ACCEPT
#
  1. Running a DNS server (tinydns) #
  2. When we run a DNS server, we have to accept UDP from anywhere to port 53 #
    iptables -A INPUT -p udp -s 0/0 -d 0/0 --destination-port 53 -j ACCEPT
#
  1. Running a Master DNS Server to update slave DNS servers #
  2. You may have your server colocated at an ISP and may arrange to have your
  3. ISP provide your primary and secondary DNS with the ISP DNS servers slaving
  4. off of your master DNS server. This has the advantage of letting you be
  5. in full control of the DNS zone files yet keeping the DNS servers exposed
  6. to the public outside of your network. To achieve this, in addition to
  7. permitting vanilla DNS responses from the ISP DNS serves, you also need
  8. to allow TCP connections from the ISP Master DNS Server: #
  9. Allow DNS zone transfers via TCP from ISP Master DNS server: #
  10. iptables -A INPUT -p tcp -s <ISP Master DNS server IP>/32 -d 0/0 --destination-port 53 --syn -j ACCEPT
#
  1. For some other custom server running here listening on port <port number>: #
    iptables -A INPUT -p tcp -s 0/0 -d 0/0 --destination-port <port number> --syn -j ACCEPT
#
  1. For FTP server, restricted to specific local hosts (and see /etc/xinetd.conf):
  2. (for public file transfers we use scp, sftp, and related SSH file transfer tools) #
    iptables -A INPUT -p tcp -s x.y.z.s/32 -d 0/0 --destination-port 20 --syn -j ACCEPT
    iptables -A INPUT -p tcp -s x.y.z.s/32 -d 0/0 --destination-port 21 --syn -j ACCEPT
    iptables -A INPUT -p tcp -s 127.0.0.1/8 -d 0/0 --destination-port 20 --syn -j ACCEPT
    iptables -A INPUT -p tcp -s 127.0.0.1/8 -d 0/0 --destination-port 21 --syn -j ACCEPT
#
  1. For Samba (smbd and nmbd), restricted to specific local client hosts (x.y.z.c): #
    iptables -A INPUT -p tcp -s x.y.z.c/32 -d x.y.z.s/32 --destination-port 139 --syn -j ACCEPT
    iptables -A INPUT -p udp -s x.y.z.c/32 -d x.y.z.s/32 --destination-port 137 -j ACCEPT

#
#Special cable modem rules. I used to have a third ethernet card,
#eth2, attached to a separate ISP via a cable modem and used the rules
#shown below to cause a specific Windows machine on my internal network
#(192.168.0.128) to send traffic out via DSL and get it back via cable.
#This violates ingres filtering rules but seems to work. It was neat
#since my cable modem had higher inbound bandwidth and it permitted
#me to do downloads without impacting my DSL inbound bandwidth.
#I no longer have that third interface, so no longer use this technique. #
#iptables -A INPUT -i eth2 -s 68.65.209.39/32 -j DROP
#iptables -A INPUT -i eth2 -s 127.0.0.0/8 -j DROP
#iptables -t nat -A POSTROUTING -s 192.168.0.128/32 -d 0/0 -j SNAT --to-source 68.65.209.39

#
  1. Finally, DENY all connection requests to any UDP port not yet provided
  2. for and all SYN connection requests to any TCP port not yet provided
  3. for. Using DENY instead of REJECT means that no 'ICMP port
  4. unreachable' response is sent back to the client attempting to
  5. connect. I.e., DENY just ignores connection attempts. Hence, use of
  6. DENY causes UDP connection requests to time out and TCP connection
  7. requests to hang. Hence, using DENY instead of REJECT may have
  8. the effect of frustrating attackers due to increasing the amount of
  9. time taken to probe ports. #
  10. Note that there is a fundamental difference between UDP and TCP
  11. protocols. With UDP, there is no 'successful connection' response.
  12. With TCP, there is. So an attacking client will be left in the dark
  13. about whether or not the denied UDP packets arrived and will hang
  14. waiting for a response from denied TCP ports. An attacker will not
  15. be able to immediately tell if UDP connection requests are simply
  16. taking a long time, if there is a problem with connectivity between
  17. the attacking client and the server, or if the packets are being
  18. ignored. This increases the amount of time it takes for an attacker
  19. to scan all UDP ports. Similarly, TCP connection requests to denied
  20. ports will hang for a long time. By using REJECT instead of DENY, you
  21. would prevent access to a port in a more 'polite' manner, but give out
  22. more information to wannabe attackers, since the attacker can positively
  23. detect that a port is not accessible in a small amount of time from
  24. the 'ICMP port unreachable' response.

iptables -A INPUT -s 0/0 -d 0/0 -p udp -j DROP
iptables -A INPUT -s 0/0 -d 0/0 -p tcp --syn -j DROP

  1. end oceanpark.com firewall rules (using iptables)
  2. -------------------------------------------------
Akcije #1

Izmjenjeno od Ernad Husremović prije više od 17 godina

  • Status promijenjeno iz Novo u Zatvoreno
Akcije

Također dostupno kao Atom PDF