001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. The ASF licenses this file to You
004: * under the Apache License, Version 2.0 (the "License"); you may not
005: * use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License. For additional information regarding
015: * copyright in this work, please see the NOTICE file in the top level
016: * directory of this distribution.
017: */
018:
019: package org.apache.roller.util;
020:
021: import java.io.BufferedReader;
022: import java.io.FileReader;
023: import java.io.FileWriter;
024: import java.io.PrintWriter;
025: import java.util.HashSet;
026: import java.util.Set;
027: import org.apache.commons.logging.Log;
028: import org.apache.commons.logging.LogFactory;
029: import org.apache.roller.config.RollerConfig;
030:
031: /**
032: * Represents a list of banned ip addresses.
033: *
034: * This base implementation gets its list from a file on the filesystem. We
035: * are also aware of when the file changes via some outside source and we will
036: * automatically re-read the file and update the list when that happens.
037: */
038: public class IPBanList {
039:
040: private static Log log = LogFactory.getLog(IPBanList.class);
041:
042: // set of ips that are banned, use a set to ensure uniqueness
043: private Set bannedIps = new HashSet();
044:
045: // file listing the ips that are banned
046: private ModifiedFile bannedIpsFile = null;
047:
048: // reference to our singleton instance
049: private static IPBanList instance = null;
050:
051: static {
052: instance = new IPBanList();
053: }
054:
055: // private because we are a singleton
056: private IPBanList() {
057:
058: log.debug("INIT");
059:
060: // load up set of denied ips
061: String banIpsFilePath = RollerConfig
062: .getProperty("ipbanlist.file");
063: if (banIpsFilePath != null) {
064: ModifiedFile banIpsFile = new ModifiedFile(banIpsFilePath);
065:
066: if (banIpsFile.exists() && banIpsFile.canRead()) {
067: this .bannedIpsFile = banIpsFile;
068: this .loadBannedIps();
069: }
070: }
071: }
072:
073: // access to the singleton instance
074: public static IPBanList getInstance() {
075: return instance;
076: }
077:
078: public boolean isBanned(String ip) {
079:
080: // update the banned ips list if needed
081: this .loadBannedIpsIfNeeded(false);
082:
083: if (ip != null) {
084: return this .bannedIps.contains(ip);
085: } else {
086: return false;
087: }
088: }
089:
090: public void addBannedIp(String ip) {
091:
092: if (ip == null) {
093: return;
094: }
095:
096: // update the banned ips list if needed
097: this .loadBannedIpsIfNeeded(false);
098:
099: if (!this .bannedIps.contains(ip)
100: && (bannedIpsFile != null && bannedIpsFile.canWrite())) {
101:
102: try {
103: synchronized (this ) {
104: // add to file
105: PrintWriter out = new PrintWriter(new FileWriter(
106: this .bannedIpsFile, true));
107: out.println(ip);
108: out.close();
109: this .bannedIpsFile.clearChanged();
110:
111: // add to Set
112: this .bannedIps.add(ip);
113: }
114:
115: log.debug("ADDED " + ip);
116: } catch (Exception e) {
117: log.error("Error adding banned ip to file", e);
118: }
119: }
120: }
121:
122: /**
123: * Check if the banned ips file has changed and needs to be reloaded.
124: */
125: private void loadBannedIpsIfNeeded(boolean forceLoad) {
126:
127: if (bannedIpsFile != null
128: && (bannedIpsFile.hasChanged() || forceLoad)) {
129:
130: // need to reload
131: this .loadBannedIps();
132: }
133: }
134:
135: /**
136: * Load the list of banned ips from a file. This clears the old list and
137: * loads exactly what is in the file.
138: */
139: private synchronized void loadBannedIps() {
140:
141: if (bannedIpsFile != null) {
142:
143: try {
144: HashSet newBannedIpList = new HashSet();
145:
146: // TODO: optimize this
147: BufferedReader in = new BufferedReader(new FileReader(
148: this .bannedIpsFile));
149:
150: String ip = null;
151: while ((ip = in.readLine()) != null) {
152: newBannedIpList.add(ip);
153: }
154:
155: in.close();
156:
157: // list updated, reset modified file
158: this .bannedIps = newBannedIpList;
159: this .bannedIpsFile.clearChanged();
160:
161: log.info(this .bannedIps.size() + " banned ips loaded");
162: } catch (Exception ex) {
163: log.error("Error loading banned ips from file", ex);
164: }
165:
166: }
167: }
168:
169: // a simple extension to the File class which tracks if the file has
170: // changed since the last time we checked
171: private class ModifiedFile extends java.io.File {
172:
173: private long myLastModified = 0;
174:
175: public ModifiedFile(String filePath) {
176: super (filePath);
177:
178: this .myLastModified = lastModified();
179: }
180:
181: public boolean hasChanged() {
182: if (lastModified() != myLastModified) {
183: return true;
184: } else {
185: return false;
186: }
187: }
188:
189: public void clearChanged() {
190: myLastModified = lastModified();
191: }
192: }
193:
194: }
|