Wednesday, November 4, 2009

B.3 Web Application Structure




I l@ve RuBoard










B.3 Web Application Structure



Each web application corresponds to a
single servlet context and exists as a collection of resources. Some
of these resources are visible to clients, while others are not. For
example, an application's JSP pages may be available
to clients, but the configuration, property, or class files that are
used by the JSP pages can be hidden. The location of components
within the application hierarchy determines whether or not clients
can see them. This allows you to make resources public or private
depending on where you put them.



Java Servlet Specification 2.3 defines the standard for web
application layout. This helps application developers by providing
conventions that indicate where to put what, along with rules that
define which parts of the application the container will make
available to clients and which parts are hidden.



Each web application corresponds to a single servlet context. In
Tomcat, these are represented by directories under the
webapps directory that serves as the
"parent" of all web applications.
Within an application directory, you'll find a
WEB-INF subdirectory, and usually other files
such as HTML pages, JSP pages, or image files. The files that are
located in the application's top-level directory are
public and may be requested by clients. The
WEB-INF directory has special significance. Its
mere presence signifies to Tomcat that its parent directory actually
represents an application. WEB-INF is thus the
only required component of a web application; it must exist, even if
it's empty. If WEB-INF is
nonempty, it typically contains application-specific configuration
files, classes, and possibly other information. Three of its most
common primary components are:


WEB-INF/web.xml



WEB-INF/classes



WEB-INF/lib


web.xml is the web application deployment
descriptor file. It gives the container a standard way to discover
how to handle the resources that make up the application. The
deployment descriptor is often used for purposes such as defining the
behavior of JSP pages and servlets, setting up access control for
protected information, specifying error pages to be used when
problems occur, and defining where to find tag libraries.



The classes and lib
directories under WEB-INF hold class files and
libraries, and sometimes other information. Individual class files go
under classes, using a directory structure that
corresponds to the class hierarchy. (For example, a class file
MyClass.class that implements a class named
com.kitebird.jsp.MyClass would be stored in the
directory classes/com/kitebird/jsp.) Class
libraries packaged as JAR files go in the lib
directory instead. Tomcat looks in the classes
and lib directories automatically when
processing requests for pages from the application. This allows your
pages to use application-specific information with a minimum of fuss.



The WEB-INF directory is also special in that it
is private. Its contents are available to the
application's servlets and JSP pages but cannot be
accessed directly through a browser, so you can place information
there that should not be displayed to clients. For example, you can
store a properties file under WEB-INF that
contains connection parameters for a database server. Or if you have
an application that allows image files to be uploaded by one page and
downloaded later by another page, putting the images into a directory
under WEB-INF makes them private. Because Tomcat
will not serve the contents of WEB-INF directly,
your JSP pages can implement an access control policy that determines
who can perform image operations. (A simple policy might require
clients to specify a name and password before being allowed to upload
images.) The WEB-INF directory is also
beneficial in that it gives you a known location for private files
that is fixed with respect to the application's root
directory, no matter what machine you deploy the application on.



Clients that attempt to circumvent the private nature of the
WEB-INF directory by issuing requests containing
names such as Web-Inf in the path will find that
its name is interpreted in case-sensitive fashion, even on systems
with filenames that are not case sensitive, such as Windows or HFS+
filesystems under Mac OS X. Note that on such systems you should take
care not to create the WEB-INF directory with a
name like Web-Inf, web-inf,
and so forth. The operating system itself may not consider the name
any different than WEB-INF, but Tomcat will. The
result is that none of the resources in the directory will be
available to your JSP pages. Under Windows, it may be necessary to
create a WEB-INF directory from the DOS prompt.
(Windows Explorer may not respect the lettercase you use when
creating or renaming a directory, just as it does not necessarily
display directory names the same way the DIR
command does from the DOS prompt.)



The preceding discussion describes web application layout in terms of
a directory hierarchy, because that's the easiest
way to explain it. However, an application need not necessarily exist
that way. A web application typically is packaged as a WAR file,
using the standard layout for components prescribed by the servlet
specification. But some containers can run an application directly
from its WAR file without unpacking it. Furthermore, a container that
does unpack WAR files is free to do so into any filesystem structure
it wishes.



Tomcat uses the simplest approach,
which is to store an application in the filesystem using a directory
structure that is the same as the directory tree from which the file
was originally created. You can see this correspondence by comparing
the structure of a WAR file to the directory hierarchy that Tomcat
creates by unpacking it. For example, the WAR file for an application
someapp can be examined using the this command:



% jar tf someapp.war


The list of pathnames displayed by the command corresponds to the
layout of the someapp directory created by
Tomcat when it unpacks the file under the
webapps directory. To verify this, recursively
list the contents of the someapp directory using
one of these commands:



% ls -R someapp                      (Unix)
C:\> dir /s someapp (Windows)


If you were to set up a context manually for an application named
myapp, the steps would be something like those
shown in the following procedure. (If you want to see what the
resulting application hierarchy should be, have a look at the
tomcat/myapp directory of the
recipes distribution.)




  • Change directory into the webapps subdirectory
    of the Tomcat directory tree.


  • Create a directory in the webapps directory with
    the same name as the application (myapp), then
    change location into that directory.


  • In the myapp directory, create a directory named
    WEB-INF. The presence of this directory signals
    to Tomcat that myapp is an application context,
    so it must exist. Then restart Tomcat so it notices the new
    application.


  • Create a short test page named page1.html in the
    myapp directory that you can request from a
    browser to make sure that Tomcat is serving pages for the
    application. This is just a plain HTML file, to avoid complications
    that might arise from use of embedded Java, tag libraries, and so
    forth:

    <html>
    <head>
    <title>Test Page</title>
    </head>
    <body bgcolor="white">
    <p>
    This is a test.
    </p>
    </body>
    </html>

    To request the page, use a URL like this, adjusting it appropriately
    for your own server hostname and port number:


    http://tomcat.snake.net:8080/myapp/page1.html



  • To try out a simple JSP page, make a copy of
    page1.html named page2.jsp.
    That creates a valid JSP page (even though it contains no executable
    code), so you should be able to request it and see output identical
    to that produced by page1.html:

    http://tomcat.snake.net:8080/myapp/page2.jsp



  • Copy page2.jsp to page3.jsp
    and modify the latter to contain some embedded Java code by adding a
    couple of lines that print the current date and client IP number:

    <html>
    <head>
    <title>Test Page</title>
    </head>
    <body bgcolor="white">
    <p>
    This is a test.
    The current date is <%= new java.util.Date( ) %>.
    Your IP number is <%= request.getRemoteAddr ( ) %>.
    </p>
    </body>
    </html>

    The Date( ) method returns the current date, and
    getRemoteAddr( ) returns the client IP number from
    the object associated with the client request. After making the
    changes, request page3.jsp from your browser and
    the output should include the current date and the IP number of the
    host from which you requested the page.




At this point, you have a simple application context that consists of
three pages (one of which contains executable code) and an empty
WEB-INF directory. For most applications,
WEB-INF will contain a
web.xml file that serves as the web application
deployment descriptor file to tell Tomcat how the application is
configured. If you look through web.xml files in
other applications that you install under Tomcat,
you'll find that they can be rather complex, but a
minimal deployment descriptor file looks like this:



<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>

</web-app>


Adding information to the web.xml file is a
matter of placing new elements between the
<web-app> and
</web-app> tags. As a simple illustration,
you can add a <welcome-file-list> element to
specify a list of files that Tomcat should look for when clients send
a request URL that ends with myapp and no
specific page. Whichever file Tomcat finds first becomes the default
page that is sent to the client. For example, to specify that Tomcat
should consider page3.jsp and
index.html to be valid default pages, create a
web.xml file in the WEB-INF
directory that looks like this:



<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>
<welcome-file-list>
<welcome-file>page3.jsp</welcome-file>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
</web-app>


Restart Tomcat so it reads the new application configuration
information, then issue a request that specifies no explicit page:


http://tomcat.snake.net:8080/myapp/


The myapp directory contains a page named
page3.jsp, which is listed as one of the default
pages in the web.xml file, so Tomcat should
execute page3.jsp and send the result to your
browser.









    I l@ve RuBoard



    Asymmetric Functions












    Asymmetric Functions


    The asymmetric EVP functions generate and manage random session keys to use for symmetric encryption and decryption by using any of the algorithms in Table 7.1 from which OpenSSL was compiled.




    int EVP_SealInit(EVP_CIPHER_CTX *ctx, EVP_CIPHER *type,
    unsigned char **ek, int *ekl, unsigned char *iv, EVP_PKEY
    **pubk, int npubk);



    EVP_SealInit () initializes a cipher context ctx for encryption. The function uses the cipher type with the initialization vector iv. You should previously initialize ctx by a call to EVP_CIPHER_CTX_init (), while type should have been acquired from a previous call to EVP_getcipherbyname (). The secret key, which is stored in ek, is encrypted by using npubk public keys stored in pubk (which enables the same encrypted data to be decrypted by using any of the corresponding private keys), ek is an array of buffers where the public key encrypted secret key is written; each buffer must contain enough room for the corresponding encrypted key. ek[i] must have room for EVP_PKEY_size (pubk [i]) bytes. The actual size of each encrypted secret key is written to ekl[i]. Upon success, the function returns 1; upon failure, the function returns 0.






    Note 

    Because a random secret key is generated, the random number generator must be seeded by using rand_seed () before calling EVP_Sealir.it (). We do not cover this interface documentation in this book, but it is available wherever OpenSSL is sold.


    At this writing, the public key must be RSA because it is the only OpenSSL public key algorithm that supports key transport.





    int EVP_SealUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out,
    int *outl, unsigned char *in, int inl);



    EVP_SealUpdate () is functionally identical to the encryption mode of EVP_CipherUpdate_ex() with a software implementation. The function uses a randomly generated symmetric key ek[n] generated with a previous call to EVP_Seallnit (). Upon success, the function returns 1; upon failure, the function returns 0.




    int EVP_SealFinal(EVP_CIPHER_CTX *ctx, unsigned char *out,
    int *outl);



    EVP_SealFinal () is functionally identical to the encryption mode of EVP_CipherFinal () with a software implementation. Upon success, the function returns 1; upon failure, the function returns 0.




    int EVP_OpenInit(EVP_CIPHER_CTX *ctx, EVP_CIPHER *type,
    unsigned char *ek, int ekl, unsigned char *iv, EVF_PKEY
    *priv);



    EVP_Openlnit () initializes a cipher context ctx for decryption. The function uses the cipher type with the initialization vector iv. You should have previously initialized ctx by a call to EVP_CIPHER_CTX_init (), while type should have been retrieved from a previous call to EVP_getelpher-byname (). The function decrypts the encrypted secret key ek of length ekl bytes by using the private key priv. Upon success, the function returns 1; upon failure, the function returns 0.





    int EVP_OpenUJ date(EVP_CIPHER_CTX *ctx, unsigned char *out,
    int *out1, unsigned char *in, int in1);




    EVP_OpenUpdate () is functionally identical to the decryption mode of EVP_CipherUpdate_ex () with a software implementation. Upon success, the function returns 1; upon failure, the function returns 0.




    int EVP_OpenFinal(EVP_CIPHER_CTX *ctx, unsigned char *out,
    int *outl);



    EVP_OpenFinal () is functionally identical to the encryption mode of EVP_CipherFinal () with a software implementation. Upon success, the function returns 1; upon failure, the function returns 0.















    Facade




















    Chapter 7 -
    Structural Patterns
    Patterns in Java, Volume 1: A Catalog of Reusable Design Patterns Illustrated with UML, Second Edition
    by Mark Grand
    John Wiley & Sons � 2002



























    Façade



    This pattern was previously described in [GoF95].




    Synopsis


    The Façade pattern simplifies access to a related set of objects by providing one object that all objects outside the set use to communicate with the set.






    Context


    Consider the organization of classes to support the creation and sending of email messages. The classes may include the following:


























    l



    A MessageBody class whose instances will contain message bodies




    l



    An Attachment class whose instances will contain message attachments that can be attached to a MessageBody object




    l



    A MessageHeader class whose instances will contain header information (to, from, subject, etc.) for an email message




    l



    A Message class whose instances will tie together a MessageHeader object and a MessageBody object




    l



    A Security class whose instances can be used to add a digital signature to a message




    l



    A MessageSender class whose instances are responsible for sending Message objects to a server that is responsible for delivering the email to its destination or to another server





    Figure 7.10 is a class diagram showing the relationships between these classes and a client class.






    Figure 7.10: Email creation

    As you can see, working with these email classes adds complexity to a client class. To use these classes, a client must know of at least these six of them, the relationships between them, and the order in which it must create instances of the classes. If every client of these classes must take on this additional complexity, it makes the email classes more difficult to reuse.


    The Façade pattern is a way to shield clients of classes like these email classes from their complexity. It works by providing an additional reusable object that hides most of the complexity of working with the other classes from client classes. Figure 7.11 is a class diagram showing this more reusable organization.






    Figure 7.11: Reusable email creation.

    In this new scheme, the portion of the Client class that was responsible for interacting with the email classes has been refactored into a separate reusable class. Client classes now need only be aware of the MessageCreator class. Furthermore, the internal logic of the MessageCreator class can shield client classes from having to create the parts of an email message in any particular order.






    Forces

















    J



    There are many dependencies between classes that implement an abstraction and their client classes. The dependencies add noticeable complexity to clients.




    J



    You want to simplify the client classes, because simpler classes result in fewer bugs. Simpler clients also mean that less work is required to reuse the classes that implement the abstraction.




    J



    You are designing classes to function in cleanly separated layers. You want to minimize the number of classes that are visible from one layer to the next.








    Solution



    Figure 7.12 is a class diagram showing the general structure of the Façade pattern. The client object interacts with a Façade object that provides necessary functionality by interacting with the rest of the objects. If there is some additional functionality that is needed by only some clients, then instead of providing it directly, the Façade object may provide a method to access another object that does provide the functionality.






    Figure 7.12: Façade pattern.

    It is not necessary for a Façade class to act as an impenetrable barrier separating client classes from the classes that implement an abstraction. It is sufficient, and sometimes better, for a Façade class to merely be a default way of accessing the functionality of the classes that implement an abstraction. If some clients need to directly access abstraction-implementing classes, then the Façade class should facilitate this with a method that returns a reference to the appropriate implementation object.


    The point of the Façade class is to allow simple clients, not require them.






    Implementation


    A Façade class should provide a way for client objects to obtain a direct reference to an instance of abstraction-implementing classes that client objects may need to know about. However, there may be some abstraction-implementing classes that client classes have no legitimate reason to know about. The Façade class should hide these classes from client classes. One way to do that is to make these classes private inner classes of the Façade class.


    Sometimes you want to vary the implementation classes that a façade object uses to accommodate variations on the abstraction being implemented. For example, returning to the email example under the Context heading, you may need a different set of classes to create MIME-, MAPI-, or Notes-compliant messages. Different sets of implementation classes usually require different Façade classes. You can hide the use of different Façade classes from client classes by applying the Interface pattern. Define an interface that all Façade classes for email creation must implement. Have client classes access the Façade class through an interface rather than directly.






    Consequences














    J



    Interposing a façade class between the classes that implement an abstraction and their clients simplifies client classes by moving dependencies from client classes to the façade class. Clients of façade objects do not need to know about any of the classes behind the façade.




    J



    Because the Façade pattern reduces or eliminates the coupling between a client class and the classes that implement an abstraction, it may be possible to change the classes that implement the abstraction without any impact on the client class.








    Java API Usage



    The java.net URL class is an example of the Façade pattern. It provides access to the contents of URLs. A class can be a client of the URL class and use it to get the contents of a URL without being aware of the many classes that operate behind the façade provided by the URL class. On the other hand, to send data to a URL, the client of a URL object may call its openConnection method, which returns the URLConnection object that the URL object uses.






    Code Example


    The following is code for the MessageCreator class shown in the class diagram under the Context heading. Instances of the MessageCreator class are used to create and send email messages. It is shown here as a typical example of a Façade class.




    public class MessageCreator {
    // Constants to indicate the type of message to create
        public final static int MIME = 1;
        public final static int MAPI = 2;
    ...
        private Hashtable headerFields = new Hashtable();
        private RichText messageBody;
        private Vector attachments = new Vector();
        private boolean signMessage;

        public MessageCreator(String to,
                              String from,
                              String subject) {
            this(to, from , subject, inferMessageType(to));
        } // Constructor(String, String, String)

        public MessageCreator(String to, String from,
                              String subject, int type) {
            headerFields.put("to", to);
            headerFields.put("from", from);
            headerFields.put("subject", subject);
    ...
        } // Constructor(String, String, String, int)

    /**
    * Set the contents of the message body.
    */
        public void setMessageBody(String messageBody) {
            setMessageBody(new RichTextString(messageBody));
        }  // setMessageBody(String)

    /**
    * Set the contents of the message body.
    */
        public void setMessageBody(RichText messageBody) {
            this.messageBody = messageBody;
        } // setMessageBody(RichText)

    /**
    * Add an attachment to the message
    */
        public void addAttachment(Object attachment) {
            attachments.addElement(attachment);
        }  // addAttachment(Object)

    /**
    * Set whether this message should be signed. The default
         * is false.
    */
        public void setSignMessage(boolean signFlag) {
            signMessage = signFlag;
        } // setSignMessage(boolean)

    /**
    * Set the value of a header field.
    */
        public void setHeaderField(String name, String value) {
            headerFields.put(name.toLowerCase(), value);
        }  // setHeaderField(String, String)

    /**
    * Send the message.
    */
        public void send() {
            ...
        }  // send()

    /**
    * Infer a message type from a destination email address.
    */
        private static int inferMessageType(String address) {
            int type = 0;
        ...
            return type;
        }  // inferMessageType(String)

    /**
    * Create a Security object appropriate for signing this
    * message.
    */
        private Security createSecurity() {
            Security s = null;
            ...
            return s;
        } // createSecurity()

    /**
    * Create a MessageSender object appropriate for the type
    * of message being sent.
    */
        private void createMessageSender(Message msg) {
    ...
        }  // createMessageSender(Message)
    ...
    }  // class MessageCreator


    The Façade pattern places no demands on the classes that the Façade class uses. Since they contain nothing that contributes to the Façade pattern, their code is not shown.






    Related Patterns



    Interface.  The Interface pattern can be used with the Façade pattern to allow different façade classes to be used without client classes being aware of the different classes.



    Law of Demeter.  A conceptual model that uses the Law of Demeter pattern (described in Patterns in Java, Volume 2) often gives rise to a design that follows the Façade pattern.



    Adapter.  The Adapter pattern is used to allow client classes to treat a single object that does not implement an interface as an object that does implement the interface. The Façade pattern can be used to allow client classes to treat a group of objects as a single object that implements a particular interface.



    Pure Fabrication.  The design of a façade class is an application of the Pure Fabrication pattern described in Patterns in Java, Volume 2.


















    Reducing Window Clutter








     

     



    Reducing Window Clutter


    While you're working on a project, it's inevitable that you'll have to use several windows within Visual Studio .NET. As windows are opened, you may find yourself running out of room to work on your source code. Luckily, Visual Studio .NET contains several window-handling features to help reduce this clutter.


    Docking


    Although present in the previous version of Visual Studio, docking windows are still worth mentioning here. With the exception of the main source code windows, all the supporting child windows within Visual Studio .NET can be docked into various positions within the IDE. Docking means that a window can be anchored to a fixed position within the IDE, as opposed to a window that is floating and covering up windows underneath it. The default layout of Visual Studio contains several windows docked to the right side and bottom of the IDE, as you've seen in several figures throughout this book.



    Auto-Hiding


    Although docking windows helps to organize your workspace, it doesn't do much to help with the clutter that could still result. The Visual Studio .NET IDE now supports auto-hiding windows. If you look at a docked window, you will see a small thumbtack icon in the upper-right corner. Once you click that icon, the window becomes an auto-hiding window. When the mouse cursor is in another part of the IDE, the auto-hiding window will collapse onto the edge of the IDE and display a small tab with the name of the window. When the mouse cursor hovers over that tab, the window will be shown. Figure B.3 shows a layout of Visual Studio .NET with the child windows automatically hidden.


    Figure B.3. Maximize your workspace by auto-hiding all the IDE child windows.




    Preset Layouts and Developer Profiles


    Visual Studio .NET can save preset window layouts. If you find that a certain window layout is better suited for a particular programming language or if you don't like the default window layout, you can use one of the preset window layouts. To change the default window layout, click View, Web Browser, Home from the main menu. This will open the Visual Studio .NET Start page. In the list of links on the left of the Start page, click the My Profile link. Within the profile page, you can change either the developer profile (which changes various settings based on the profile you choose) or individual settings, such as keyboard and (as just mentioned) window layouts. Figure B.4 shows the My Profile page.


    Figure B.4. Change the Visual Studio .NET IDE to support your individual programming style.




    New Developer Studio Windows


    In addition to all the new features added to Visual Studio .NET, a few new windows have been added to the IDE:



    • Solution Explorer.
      The Solution Explorer is an enhancement to the File View present in the previous version of Visual Studio. The enhancement is primarily in the way icons are displayed based on the language used for the project. Also, the Solution Explorer displays all the projects contained within a single solution.



    • Command window.
      The Command window is designed for manually entering in automation commands. The IDE, like its predecessor, contains several automation commands that can be used by COM-enabled applications. With the Command window, you can enter the available commands to invoke these methods. Open the Command window by clicking View, Other Windows, Command Window. Enter the command File.AddNewProject. The Add New Project dialog will be displayed, as shown in Figure B.5.


      Figure B.5. Use the command window to perform automation tasks.




    • Server Explorer.
      The Server Explorer acts as a server-management application within Visual Studio .NET. It allows you to open data connections and browse databases located on the local machine or on the network. The Server Explorer also lets you drag and drop nodes onto various designers within Visual Studio .NET.














     

     





    Top

    Section 9.3. Applying Participants to a Timing Diagram










    9.3. Applying Participants to a Timing Diagram





    First, you need to create a timing diagram that incorporates all of the participants involved in the Create a new Regular Blog Account interaction, as shown in Figure 9-4.


    The full participant names have been left out of Figure 9-4 to keep the diagram's size manageable, although you could equally have included the full <name>:<type> format for the title of a participant.


    Another feature that is missing from Figure 9-4 is the participants that are created and destroyed within the life of the interaction: the :AuthorDetails and :RegularBlogAccountparticipants. Details of these participants have been left out because timing diagrams focus on timing in relation to state changes. Apart from being created and/or destroyed, the :AuthorDetails and :RegularBlogAccount participants do not have any complicated state changes; therefore, they are omitted because they would not add anything of interest to this particular diagram.


    During system modeling activities, you will need to decide what should and should not be explicitly placed on a diagram. Ask yourself, "Is this detail important to understanding what I am modeling?" and "Does including this detail make anything clearer?" If the answer is yes to either of these questions, then it's best to include the detail in your diagram; otherwise, leave the additional detail out. This might sound like a fairly crude rule, but it can be extremely effective when you are trying to keep a diagram's clutter to a minimum.




    Figure 9-4. The names of the main participants involved in an interaction are written vertically on the lefthand side of a timing diagram














    Summary




    [ Team LiB ]









    Summary


    CSS allows authors to strip their markup down to structure and style. To optimize your CSS, remove as much whitespace and as many comments as you can, and use short class and id names. Use simple, high DOM-level type selectors and avoid the specific; be as vague and abstract as possible to apply your style in wide swaths across types of structural elements (all body text, paragraphs, or dts, for example). Group selectors and declarations and use shorthand properties to minimize your CSS rule sets. Finally, minimize HTTP requests by grouping external style sheets and embedding where necessary. Here is a list of the topics covered in this chapter:



    • Embed or SSI abbreviated styles for maximum speed.


    • Minimize HTTP requests by grouping external CSS files.


    • Link to external style sheets site-wide to cache in.


    • Layer style sheets for speed. Use cascading to combine linked, alternate, and imported style sheets to layer your presentation for older browsers and alternate media (print), and to save bandwidth.


    • Group selectors with the same declarations and declarations with the same selectors.


    • Use simple selectors high in the document tree to set global and element-wide styles (that is, type styles like body, h1, p, and dt).


    • Use descendant selectors to get specific without class or id selectors.


    • Take advantage of your inheritance�don't overspecify CSS; let it flow down the document tree.


    • Use multiple classes to group common style declarations to save space.


    • Use value replication on the border, padding, and margin properties.


    • Use shorthand hex colors (such as #00f).


    • Use shorthand properties to optimize your CSS (including font, background, margin, and border).


    • Use short class and id names.


    • Use shorthand hexadecimal colors or names, whichever is shorter.


    • Use relative lengths for maximum flexibility.


    • Remove whitespace.


    • Cut the comments.









      [ Team LiB ]



      Packet Filtering













      Packet Filtering

      While packet filtering rules come last in /etc/pf.conf, understanding packet filtering is essential to using PF. People use PF without going near address translation, redirection, or any of the other nifty PF features, but packet filtering is the destination for many people. You could say that the entire function of PF is to "filter packets": allow packets with this TTL or higher, sieve out fragments, and so on. In this context, however, packet filtering has a very specific meaning: providing access control for network packets by source, destination, protocol, and other packet characteristics.




      What Packet Filtering Doesn't Do


      Packet filtering controls network connections based entirely on TCP/IP protocols and protocol characteristics, such as ports. If you want to stop all connections coming from a particular block of IP addresses, packet filtering is your friend. If you only want to allow connections to a particular TCP/IP port, packet filtering will work for you. If you want to allow entrance only to packets with the ECN flag set, but no other flags, PF will do that without even questioning why you would want to do such a weird thing. You can also filter other protocols that operate at a logical protocol layer such as IPSec, SKIP, VINES, and so on, but only on the logical network protocol. If it's a different protocol layer, PF cannot even see it.


      One common question is, "How do I use PF to filter based on Ethernet MAC addresses?" The answer is, "You don't." MAC addresses are part of a physical protocol and are in a different layer. You might as well ask how one could use PF to filter dial-up connections. (Also, don't forget that MAC addresses are easily changed, and filtering based on them is more trouble than the security gained in almost all environments.) Mind you, OpenBSD does have a tool to filter based on MAC address, brconfig(8). But it's not part of PF.


      Also, PF doesn't know anything about applications or application protocols. If you allow TCP/IP connections to port 25 on a server within your network, you might think you're allowing connections to the mail server on that host. Actually, you're allowing the connection to whatever daemon happens to be running on port 25 on that host! PF does not and never will recognize a SMTP data stream; it only sees that the connection is going to port 25 on that host, and allows it.


      At one time, I had a system on the Net running an ssh daemon on ports 25 (email), 80 (web), 110 (POP3), 443 (secure web), and several other popular TCP/IP ports so that I could saunter past whatever packet-filtering firewall I happened to be behind that day. It made a very effective demonstration of exactly why I thought that company's security system could stand improvement.





      Packet Filtering Rule Design


      We took a brief look at the design of a PF rule earlier this chapter. Let's completely dissect this same rule to identify each piece.




      1 pass 2 in 3 on fxp0 4 proto tcp 5 from any 6 to 192.168.1.1 7 port 22 8 keep state


      The 1 first part of the rule is the keyword that tells PF how to process this particular rule. Every packet-filtering rule begins with either "pass" or "block." We then state if this rule applies to packets 2 entering (in) or leaving (out) the system. This rule applies to a 3 particular interface.


      We then have several statements to define the characteristics of the connection that this rule matches — a regular expression for TCP/IP, as it were. This rule applies to 4 TCP connections 5 from any IP address, if the connection is made 6 to the IP address 192.168.1.1 on 7 port 22. Finally, if the rest of the rule matches and the connection is allowed, we 8 keep state for the connection.


      Each sort of rule has a slightly different syntax, depending on the type of protocol being filtered. For example, ICMP has no port numbers, so the rules are written slightly differently. Their own modifiers can follow some keywords. We'll see examples of all of these throughout this chapter.





      Pass and Block


      Each packet-filtering rule begins with one of two keywords: pass or block. Pass rules allow traffic that matches the pattern specified in the rule to continue. The trick lies in specifying the pattern that matches only the packets you want to pass.



      Block rules are similar, but they have a wide range of possible responses. What, exactly, should happen when a packet is rejected? PF can give several types of responses, depending on the protocol you are using and your desired behavior.


      The default is to silently drop rejected packets, but this can be adjusted on a global level by the block-policy option (see "Blocked Packet Policy"). You can also decide how to respond to blocked packets on a rule-by-rule basis.


      Dropped packets are simply rejected without notifying the client. The effects of this vary widely depending on the sort of connection and the type of client. In most cases, the client will wait until the protocol times out and then complain that it could not make a connection or that the connection was lost. While this is the default, you can set it explicitly to override a default policy.




      block drop in all


      You can make your system respond politely to TCP requests and say, "No, I'm not going to accept that connection" by using the "return-rst" response. As it implies, this returns a RST (reset) for any matching attempted connection. This only works for rules that only match TCP packets — if you do not specify the protocol, you will get a syntax error. The following example sends a RST for every incoming TCP connection request:




      block return-rst in proto tcp all


      This only affects TCP packets, however. PF includes the "return" keyword, which returns an RST for TCP connections and an ICMP UNREACHABLE message for UDP requests and silently drops everything else. This is the same as the "block-policy" option.




      block return in all


      You can also specify particular types of ICMP responses for matching packets. This defaults to the standard "port unreachable" ICMP type 3 message, but you can choose to override it and return a more specific ICMP code. The effects of this will vary depending on the error code returned; if you are not conversant with ICMP error messages, either take the default and like it or learn the proper ICMP code to return in each circumstance. Getting this wrong is an excellent way to annonuce that you have a misconfigured firewall, you don't know what you're doing, and would some kind hacker please show you the error of your ways?





























































      ICMP Code




      PF Name




      Description



      0



      net-unr



      Network Unreachable



      1



      host-unr



      Host Unreachable



      2



      proto-unr



      Protocol Unreachable



      3



      port-unr



      Port Unreachable



      4



      needfrag



      Fragmentation Needed



      5



      srcfail



      Source Route Failed



      6



      net-unk



      Destination Network Unknown



      7



      host-unk



      Destination Host Unknown



      8



      isolateSource



      Host Isolated



      9



      net-prohib



      Destination Network Administratively Prohibited



      10



      host-prohib



      Destination Host Administratively Prohibited



      11



      net-tos



      Network Unreachable for Terms of Service



      12



      host-tos



      Host Unreachable for Terms of Service



      13



      filter-prohib



      Communication Administratively Prohibited by Filtering



      14



      host-preced



      Host Precedence Violation



      15



      cutoff-preced



      Precedence Cutoff in Effect




      If you just want the standard "icmp unreachable" message, use the "return-icmp" statement.




      block return-icmp in all


      Alternately, if you know which ICMP code you want to return, you can specify the code name or number in parenthesis after the return-icmp statement. If you to return a polite message telling clients that they may not connect to your network, for example, you might want to use ICMP code 13, "filter-prohib."




      block return-icmp(filter-prohib) in all


      If you're seriously interested in ICMP filtering, uses, and the effect of filtering and returning various sorts of ICMP responses, I recommend you check out Ofir Arkin's "ICMP Usage in Scanning" at http://www.sys-security.com/html/projects/icmp.html.



      Default Pass or Default Block


      Out of the box, PF uses a "default pass" stance. This is very simple to change with two rules at the beginning of /etc/pf.conf.




      block in all
      block out all


      Now, nothing will go in or out unless you explicitly create a rule allowing it.






      Additional Actions in Rules


      You can use a couple of keywords here to specify actions that the PF system should take upon matching a packet to a rule. If you specify the "log" keyword immediately after the "in" or "out," a log message is sent to the pflogd(8) daemon (see "PF Logging"). If pflogd is not running, no log is kept. If this rule includes a "keep state" or "modulate state" statement; only the packet that establishes state is logged. If you want to log all the packets in stateful inspection connections, use the "log-all" option instead of just plain "log." All packets that match that rule, not just the initial packet, will be logged.




      block return in log-all


      You can tell PF to stop processing the rules when a packet matches a particular rule. Remember, rules are processed in order: If you have a rule that allows a connection and a later rule that disallows that connection, you can use the "quick" keyword to prevent PF from ever reaching that later rule. This makes it safe to have a "block all" rule last in /etc/pf.conf, and it can accelerate PF on long rule lists. Remember, all rules are processed in order.




      pass in quick proto tcp from any to $ext_if port 22 keep state


      The "quick" keyword must appear after the "log" or "log-all" keyword or the "direction" keyword if you are not logging. The PF developers discourage use of the quick keyword, as you should be able to achieve the same results with a properly-written ruleset.





      Packet Pattern Matching


      One of the most intensive parts of PF is the syntax used to describe packets. The next several terms in a rule describe particular sorts of packet by protocol, port, direction, and various other characteristics. PF will compare each arriving packet to these rules. If the rule matches the packet description, it will be treated as you decide. These terms must be specified in the order presented here. A term can be skipped, but the terms that appear must be in order.



      Interface Matching


      The "on" keyword describes an interface that this rule applies to. You must specify an interface, either explicitly or with a macro. If you want a rule to match every interface on the machine, you can use the "all" interface name. Here we stop all traffic coming in on interface fxp0 and allow traffic out on whatever interface is represented by the macro $external_if:




      block in on fxp0
      pass out on $external_if




      Address Families


      You could list an protocol address family, either "inet" for IPv4 or "inet6" for IPv6, to state that this rule only applies to packets in that type of address. The inet address family includes the IP, ICMP, TCP, and UDP protocols. The inet6 family includes the IPv6, ICMPv6, TCP, and UDP protocols. While TCP and UDP are common to both families, IPv6 and ICMPv6 are extremely different from IP and ICMP. The following rules allow standard IP traffic but deny IPv6 traffic:





      pass in inet
      block in inet6




      Network Protocol


      In addition to the inet and inet6 families, PF can recognize almost any network protocol by number or name. The "proto" keyword tells PF to filter by protocol. Network protocols can be listed by name, as given in /etc/protocols, or by protocol number. For example, here is a rule that allows SKIP traffic (protocol 57) to pass through the packet filter:




      pass in proto 57


      Obviously, this functionality somewhat overlaps the inet and inet6 statements — you could have a statement that explicitly allowed the IP, ICMP, TCP, and UDP protocols.




      Address and Port


      The next set of statements is the most commonly used type of packet-filtering rule, identifying source and destination addresses and ports. The syntax is very simple:




      from source-address port source-port to destination-address port destination-port


      Addresses here can be specific IP addresses or netblocks in CIDR notation (such as /24, /22, and so on, as discussed in Chapter 8). You could also use the keyword "any," meaning "any address." For example, this rule allows connections from anywhere on the Internet to the IP address 192.168.1.5:




      pass in from any to 192.168.1.5


      You could also specify an address as "no-route," meaning "any address which is not currently routable." If your OpenBSD machine does not know how to get to an IP address, the no-route address matches. It's usually a good idea to drop packets for unreachable hosts — even if they are legitimate, your system cannot respond to them. (This can only happen on systems without a default route, of course.) See Chapter 8 for a discussion of routing.


      Interface and host names can also be used in the address space. PF will automatically translate these to IP addresses when loading the rules. Here, for example, we are allowing the machine 192.168.1.200 to connect to anything on the fxp0 interface:




      pass in from 192.168.1.200 to fxp0


      When you activate these rules and check them within PF, you'll see that the live rules contain the actual IP addresses on interface fxp0.



      Ports can be specified as numbers or as names as found in /etc/services. Port numbers exist only in the TCP and UDP protocols, so when you specify a port you must specify the protocol being used. Use of the port keyword is optional in both source and destination; if you don't care which port a connection is coming from or going to, do not include a port statement. Here, we tighten the previous rule to specify that only TCP connections to port 22 are permitted:




      pass in proto tcp from any to 192.168.1.5 port 22


      Remember, this is not the same as only allowing SSH connections! PF doesn't know what application protocol you're using; it only knows about the TCP/IP port you are permitting.


      If you know the source port of a connection, you can easily specify that on the rule line. For example, many old firewalls make all of their outbound DNS queries from UDP port 53. Here, we allow the nameserver running on our PF-protected host to make queries of our ISP's nameserver. We're also specifying that packets may return back to this service:




      1 pass out proto udp from 192.168.1.5 port 53 to 10.15.3.8 port 53
      2 pass in proto udp from 10.15.3.8 port 53 to 192.168.1.5 port 53


      Note that we specify 1 "pass out" in the first rule so that packets can leave this system and 2 "pass in" on the second rule so that the responses may come back. As DNS queries run over UDP, we restrict this to UDP queries only. (In a little bit, we'll see how to write this sort of rule more securely and as a single line with stateful inspection.)




      User and Group


      PF allows you to filter by the user and group of the socket opened by the program trying to access the network. This functionality can only work when connections originate with or terminate at the PF device; you cannot use this on a network-protecting firewall to protect hosts within the network. In other words, if you're running a web server on your OpenBSD machine, you can use PF only allow connections to port 80 if the web server user has opened the connection, but if you're using your OpenBSD machine to protect another web server the user and group ID will not work. Also, this only works with TCP or UDP protocols; if you try to filter other protocols such as ICMP by user, the restriction will be ignored.


      A "user" or a "group" keyword followed by a name or UID/GID activates this functionality, such as:




      user username


      Add this after your packet address and port statement. For example, here we allow anyone in the wheel group to make outbound SSH connections from this machine:





      pass out on fxp0 proto tcp from any to any port 22 group wheel


      Be careful restricting user functionality; you might be surprised what sorts of connectivity a shell user might need! If you don't have interactive shell users, and none of your users should be running programs on the server, you might consider a rule such as this:




      block out on fxp0 proto tcp from any to any group customers


      In the event of a user account compromise, or if some FTP-only customer even manages to break out into a shell, he won't be able to initiate any outbound connections from your system. This will seriously restrict the intruder's ability to use your server to attack other servers, which is always nice. The downside is, he'll have time to spend trying to break root on your server instead. Are you certain all of your programs are secure? [3]




      Packet Flags


      PF allows you to filter based upon TCP packet flags. A packet flag is a flag that indicates the state of the connection that the packet claims to be a part of. For example, when a client sends a SYN packet to a server, that packet includes a flag that says "I'm a SYN packet." The returning SYN+ACK packet will have two flags set, the SYN flag and the ACK flag. TCP packets have many different possible flags, each with its own purpose.


      If you're going to start complex filtering based on TCP flags, you must be completely intimate with TCP/IP. You will see many sites on the Internet that claim that if you filter on such-and-such flags, you will get a particular useful behavior. Research these claims carefully. The problem is that every TCP/IP stack has been modified by vendors for their own purposes [4] and behaves in a slightly different way. You may find a description of a neat filtering-on-flags trick that can prevent port scans from working, for example, but then discover that some of your desktop systems crash whenever they try to access the Internet. If you want to really get into flag-based filtering, get a copy of all three volumes of TCP/IP Illustrated and don't just read it; assimilate it, live it, commune with it, become one with it. Ambitious flag-based filtering is of questionable efficacy, and (in my opinion) the single part of firewall construction most laden with uncertainty, error, and superstition.



      Simple flag-based packet filtering help manage multi-interface firewalls. If you want to filter connections through one machine to your sales office, your financial network, your DMZ, the factory in Shaolin China, and the public Internet, the only way to differentiate traffic flows is on which flags are set in each packet. PF recognizes the following flags.





































      Flag




      Name



      F



      FIN



      S



      SYN



      R



      RST



      P



      PUSH



      A



      ACK



      U



      URG



      E



      ECE



      W



      CWR




      We will discuss certain precise combinations of flags that can be used in various situations. Using other combinations of flags leaves you on your own.


      The general syntax of a flag statement is:




      flags 1 set / 2 list


      This rule matches a packet that has certain flags 1 set out of a 2 list of flags. One popular example is:




      flags S/SA


      PF will check the "S" and "A" flags on every packet. If the "S" flag is set, and the "A" flag is not set, this rule matches. This rule doesn't care if, say, "R" or "E" or any other flag is set, because it's not in the list. This is a typical "connection creation" rule; packets that are sent by one machine requesting access to a another have the SYN flag set, but the ACK flag not set. This is commonly referred to as a "SYN packet."


      You can also specify lists that cannot be set, such as this:




      flags /SFRA


      A matching packet has none of the flags S, F, R, and A set.


      If you're only concerned about one flag, you can specify it on both sides of the slash. Here, matching rules have the SYN flag set, and the other flags are irrelevant:




      flags S/S



      Add the flag statement after the address and port statement in your PF rule. Here, we are allowing any machine on the Internet to request a TCP connection to our web server:




      pass in proto tcp from any to 192.168.1.5 port 80 flags S/SA


      If the packet has the SYN flag set, and the ACK flag is not set, the connection will be allowed. If both the SYN and ACK flags are set, this rule does not match.




      Filtering on Flags and Port Scanners


      In most cases, filtering based on flags is just over-engineering with very little net benefit. One popular use for flag-based filtering is to confound network scanners such as nmap that use the characteristics of an operating system's responses to bad packets to identify an operating system. While this is of questionable efficiency — the intruder will just use some other method to identify the operating system — PF can provide some basic protection against these sorts of probes with the following rules:




      block in quick proto tcp all flags SF/SFRA
      block in quick proto tcp all flags SFUP/SFRAU
      block in quick proto tcp all flags FPU/SFRAUP
      block in quick proto tcp all flags /SFRA
      block in quick proto tcp all flags F/SFRA
      block in quick proto tcp all flags U/SFRAU
      block in quick proto tcp all flags P




      ICMP Types and Codes


      Much like TCP flags, ICMP has types and codes. Despite what you might hear, it is not proper to unilaterally block ICMP. ICMP has a vital role to play in many sorts of connections. Fortunately, most ICMP needs are handled very easily by the provided block policies.


      You can allow particular types of ICMP traffic with the "icmp-type" keyword.




      icmp-type type code code


      For example, here's how you allow incoming ping requests. This doesn't allow the responses, but it will let the requests into your system. (Adding stateful inspection would let the transaction complete, but we haven't discussed stateful inspection yet.)




      pass in inet proto icmp icmp-type 8 code 0


      Everything I said about filtering by TCP flags applies doubly to filtering ICMP. You must really understand TCP/IP before you start playing with ICMP filtering.





      IP Options


      Unless you specifically allow packets containing IP options, PF will block them. The "allow-opts" keyword tells PF to accept matching packets if they contain IP options.


      With the packet description language presented here, you can describe almost any TCP/IP packet and give basic descriptions of packets of most other protocols. While passing and blocking is theoretically all you need to do with packets, PF includes some options to make managing packets easier.




      Type of Service


      Every TCP packet includes a Type of Service field. The setting of this field varies with the application protocol; each application requests a particular Type of Service setting. You will need to study your particular application to determine what Type of Service your application uses (or, just drop a packet sniffer on the network and see what it says). PF can match packets on Type of Service with the "tos" keyword. Here we allow an application protocol to pass when it has a Type of Service of 0x10, but reject it when it has a Type of Service of 0x08:




      pass out on fxp0 proto tcp from any to any port 88 tos 0x10
      block out on fxp0 proto tcp from any to any port 22 tos 0x08


      Applications can change the requested Type of Service after the connection is set up, making filtering based on Type of Service very tricky. In "Bandwidth Management," we'll see an example of using Type of Service to offer different service levels to different parts of an application.






      Labels


      Your /etc/pf.conf file should certainly be well commented, with labels for each major section describing the desired effect so your coworkers can have some idea what was going through your mind when they get paged at 3 a.m. to diagnose a problem. But you can also use labels visible to pfctl(8). These labels have no operational effect whatsoever, but can help you manage your system. Labels can be useful for parsing rule output for billing purposes, for example. To use a label, add the "label" keyword and a label name to the end of your rule.




      pass out proto tcp from any to any port 22 1 label 2 ssh


      We have the label at the 1 end of the rule and a simple 2 label name. In addition to these simple text names, you can use macros within label names. PF provides several macros for label names. When you use a macro, the label name must be in double quotes (").





























      $if



      Interface name




      $srcaddr



      Source IP address




      $dstaddr



      Destination IP address




      $srcport



      Source port description




      $dstport



      Destination port description




      $proto



      Protocol name




      $nr



      Rule number




      These macros are parsed when the rules are first loaded; you can't dynamically build a list of labels from the packets that pass through your firewall. If a macro references a field with an "any" value, the macro also shows up as "any." For example, our sample label rule above doesn't list an interface name. Let's use the $if macro in the rule name:




      pass out proto tcp from any to any port 22 label "$if:ssh"


      When you load the rules and run them, the label will show up as "any:ssh." The rule doesn't mention an interface, so the rule applies to any interface, and the label macro knows it. Macros for IP address and port are most useful when applied to macros for groups of servers or ports: Each generated rule will be separately labeled.




      pass in proto tcp from any to $Webservers port 22 label 1 "ssh:$dstaddr"


      This will generate a separate rule for each web server, each with its own label named after the IP address of the web server.


      One thing to note is that you can use the same label multiple times within a rule. I could put the string "label ftp" in several FTP-related rules, and they would each show up as a separate lines with the same name when viewing the statistics, like this. Or, if I have a rule with brackets to allow multiple protocols or addresses, it will expand to have multiple rules with the same label. For example, this rule creates multiple labels called "web":




      pass out proto tcp from ($ExtIf) to any port {80, 443} label web


      If you want separate labels for these, try combining the label with the macro for the destination port, like this:




      pass out proto tcp from ($ExtIf) to any port {80, 443} label "web:$dstport"


      This would create two labels, called "web:80" and "web:443."





      Anchors and Named Rulesets


      PF supports the ability to add attachment points for rules. You can define an attachment point, or anchor, so that when a packet reaches the anchor point in the rules list, the rules in that attachment point are interpreted. At first glance, this seems rather pointless — why not just put the rules you want to have executed where you want them executed, instead of using an attachment point and some fancy redirection?



      The clever bit is that outside programs can add rules into anchor points! Your IDS can add rules to block an IP address when it detects an attack, although with the current state of IDS technology this tends to block legitimate activities too frequently. Your mail server can use this to block known spam sources (see spamd(8)). Your authentication system can add rules to your firewall when a user logs in. We discuss OpenBSD's integrated authpf(8) features in Chapter 19, which makes heavy use of anchors. Most of these functions require a bit of programming, or at least shell scripting.


      PF supports the following types of anchors.




















      nat-anchor



      An anchor for NAT rules




      rdr-anchor



      An anchor for redirection rules




      binat-anchor



      An anchor for bi-directional NAT rules




      anchor



      An anchor for packet-filtering rules




      In pf.conf, an anchor appears like this:




      anchortype anchorname


      For example, an anchor called "intrusion-detection" would appear as:




      anchor intrusion-detection


      You cannot put anchors within anchors.


      We'll look at an example of anchor use in Chapter 19.







      [3]Of course, if the user account can use CGI programs, the intruder could just run a program with the permissions of the "www" user. Isn't security fun?





      [4]I have been told that this purpose is not "Make Michael's life difficult," but am still awaiting hard evidence to back this assertion.