Skip to content

Commit a482447

Browse files
committed
Create metric: appsec.waf.error
1 parent a47c3ce commit a482447

File tree

5 files changed

+135
-4
lines changed

5 files changed

+135
-4
lines changed

dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/AppSecRequestContext.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,9 @@ public class AppSecRequestContext implements DataBundle, Closeable {
130130
private volatile int raspInternalErrors;
131131
private volatile int raspInvalidObjectErrors;
132132
private volatile int raspInvalidArgumentErrors;
133+
private volatile int wafInternalErrors;
134+
private volatile int wafInvalidObjectErrors;
135+
private volatile int wafInvalidArgumentErrors;
133136

134137
// keep a reference to the last published usr.id
135138
private volatile String userId;
@@ -157,6 +160,17 @@ public class AppSecRequestContext implements DataBundle, Closeable {
157160
AtomicIntegerFieldUpdater.newUpdater(
158161
AppSecRequestContext.class, "raspInvalidArgumentErrors");
159162

163+
private static final AtomicIntegerFieldUpdater<AppSecRequestContext> WAF_INTERNAL_ERRORS_UPDATER =
164+
AtomicIntegerFieldUpdater.newUpdater(AppSecRequestContext.class, "wafInternalErrors");
165+
private static final AtomicIntegerFieldUpdater<AppSecRequestContext>
166+
WAF_INVALID_OBJECT_ERRORS_UPDATER =
167+
AtomicIntegerFieldUpdater.newUpdater(
168+
AppSecRequestContext.class, "wafInvalidObjectErrors");
169+
private static final AtomicIntegerFieldUpdater<AppSecRequestContext>
170+
WAF_INVALID_ARGUMENT_ERRORS_UPDATER =
171+
AtomicIntegerFieldUpdater.newUpdater(
172+
AppSecRequestContext.class, "wafInvalidArgumentErrors");
173+
160174
// to be called by the Event Dispatcher
161175
public void addAll(DataBundle newData) {
162176
for (Map.Entry<Address<?>, Object> entry : newData) {
@@ -222,6 +236,22 @@ public void increaseRaspErrorCode(int code) {
222236
}
223237
}
224238

239+
public void increaseWafErrorCode(int code) {
240+
switch (code) {
241+
case DD_WAF_RUN_INTERNAL_ERROR:
242+
WAF_INTERNAL_ERRORS_UPDATER.incrementAndGet(this);
243+
break;
244+
case DD_WAF_RUN_INVALID_OBJECT_ERROR:
245+
WAF_INVALID_OBJECT_ERRORS_UPDATER.incrementAndGet(this);
246+
break;
247+
case DD_WAF_RUN_INVALID_ARGUMENT_ERROR:
248+
WAF_INVALID_ARGUMENT_ERRORS_UPDATER.incrementAndGet(this);
249+
break;
250+
default:
251+
break;
252+
}
253+
}
254+
225255
public int getWafTimeouts() {
226256
return wafTimeouts;
227257
}
@@ -243,6 +273,19 @@ public int getRaspError(int code) {
243273
}
244274
}
245275

276+
public int getWafError(int code) {
277+
switch (code) {
278+
case DD_WAF_RUN_INTERNAL_ERROR:
279+
return wafInternalErrors;
280+
case DD_WAF_RUN_INVALID_OBJECT_ERROR:
281+
return wafInvalidObjectErrors;
282+
case DD_WAF_RUN_INVALID_ARGUMENT_ERROR:
283+
return wafInvalidArgumentErrors;
284+
default:
285+
return 0;
286+
}
287+
}
288+
246289
public Additive getOrCreateAdditive(PowerwafContext ctx, boolean createMetrics, boolean isRasp) {
247290

248291
if (createMetrics) {

dd-java-agent/appsec/src/main/java/com/datadog/appsec/powerwaf/PowerWAFModule.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -451,9 +451,8 @@ public void onDataAvailable(
451451
reqCtx.increaseRaspErrorCode(e.code);
452452
WafMetricCollector.get().raspErrorCode(gwCtx.raspRuleType, e.code);
453453
} else {
454-
// TODO APPSEC-56703
455-
// reqCtx.increaseWafErrorCode(e.code);
456-
// WafMetricCollector.get().wafErrorCode(e.code);
454+
reqCtx.increaseWafErrorCode(e.code);
455+
WafMetricCollector.get().wafErrorCode(gwCtx.raspRuleType, e.code);
457456
}
458457
return;
459458
} finally {

dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/gateway/AppSecRequestContextSpecification.groovy

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,4 +303,17 @@ class AppSecRequestContextSpecification extends DDSpecification {
303303
ctx.getRaspError(AppSecRequestContext.DD_WAF_RUN_INVALID_ARGUMENT_ERROR) == 0
304304
ctx.getRaspError(0) == 0
305305
}
306+
307+
def "test increase and get WafErrors"() {
308+
when:
309+
ctx.increaseWafErrorCode(AppSecRequestContext.DD_WAF_RUN_INTERNAL_ERROR)
310+
ctx.increaseWafErrorCode(AppSecRequestContext.DD_WAF_RUN_INTERNAL_ERROR)
311+
ctx.increaseWafErrorCode(AppSecRequestContext.DD_WAF_RUN_INVALID_OBJECT_ERROR)
312+
313+
then:
314+
ctx.getWafError(AppSecRequestContext.DD_WAF_RUN_INTERNAL_ERROR) == 2
315+
ctx.getWafError(AppSecRequestContext.DD_WAF_RUN_INVALID_OBJECT_ERROR) == 1
316+
ctx.getWafError(AppSecRequestContext.DD_WAF_RUN_INVALID_ARGUMENT_ERROR) == 0
317+
ctx.getWafError(0) == 0
318+
}
306319
}

internal-api/src/main/java/datadog/trace/api/telemetry/WafMetricCollector.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,13 @@ private WafMetricCollector() {
4646
new AtomicLongArray(RuleType.getNumValues());
4747
private static final ConcurrentMap<Integer, AtomicLongArray> raspErrorCodeCounter =
4848
new ConcurrentSkipListMap<>();
49+
private static final ConcurrentMap<Integer, AtomicLongArray> wafErrorCodeCounter =
50+
new ConcurrentSkipListMap<>();
4951

5052
static {
5153
for (int i = -1 * ABSTRACT_POWERWAF_EXCEPTION_NUMBER; i < 0; i++) {
5254
raspErrorCodeCounter.put(i, new AtomicLongArray(RuleType.getNumValues()));
55+
wafErrorCodeCounter.put(i, new AtomicLongArray(RuleType.getNumValues()));
5356
}
5457
}
5558

@@ -121,6 +124,10 @@ public void raspErrorCode(final RuleType ruleType, final int ddwafRunErrorCode)
121124
raspErrorCodeCounter.get(ddwafRunErrorCode).incrementAndGet(ruleType.ordinal());
122125
}
123126

127+
public void wafErrorCode(final RuleType ruleType, final int ddwafRunErrorCode) {
128+
wafErrorCodeCounter.get(ddwafRunErrorCode).incrementAndGet(ruleType.ordinal());
129+
}
130+
124131
public void missingUserLogin(final LoginFramework framework, final LoginEvent eventType) {
125132
missingUserLoginQueue.incrementAndGet(
126133
framework.ordinal() * LoginEvent.getNumValues() + eventType.ordinal());
@@ -242,6 +249,10 @@ public void prepareMetrics() {
242249
new RaspError(counter, ruleType, WafMetricCollector.wafVersion, i))) {
243250
return;
244251
}
252+
if (!rawMetricsQueue.offer(
253+
new WafError(counter, ruleType, WafMetricCollector.wafVersion, i))) {
254+
return;
255+
}
245256
}
246257
}
247258
}
@@ -422,6 +433,31 @@ public RaspError(
422433
}
423434
}
424435

436+
public static class WafError extends WafMetric {
437+
public WafError(
438+
final long counter,
439+
final RuleType ruleType,
440+
final String wafVersion,
441+
final Integer ddwafRunError) {
442+
super(
443+
"waf.error",
444+
counter,
445+
ruleType.variant != null
446+
? new String[] {
447+
"rule_type:" + ruleType.type,
448+
"rule_variant:" + ruleType.variant,
449+
"waf_version:" + wafVersion,
450+
"event_rules_version:" + rulesVersion,
451+
"waf_error:" + ddwafRunError
452+
}
453+
: new String[] {
454+
"rule_type:" + ruleType.type,
455+
"waf_version:" + wafVersion,
456+
"waf_error:" + ddwafRunError
457+
});
458+
}
459+
}
460+
425461
public static class AtomicRequestCounter {
426462

427463
private final AtomicLong atomicLong = new AtomicLong();

internal-api/src/test/groovy/datadog/trace/api/telemetry/WafMetricCollectorTest.groovy

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@ class WafMetricCollectorTest extends DDSpecification {
3636
WafMetricCollector.get().raspRuleEval(RuleType.SQL_INJECTION)
3737
WafMetricCollector.get().raspTimeout(RuleType.SQL_INJECTION)
3838
WafMetricCollector.get().raspErrorCode(RuleType.SHELL_INJECTION, DD_WAF_RUN_INTERNAL_ERROR)
39+
WafMetricCollector.get().wafErrorCode(RuleType.SHELL_INJECTION, DD_WAF_RUN_INTERNAL_ERROR)
3940
WafMetricCollector.get().raspErrorCode(RuleType.SQL_INJECTION, DD_WAF_RUN_INVALID_OBJECT_ERROR)
41+
WafMetricCollector.get().wafErrorCode(RuleType.SQL_INJECTION, DD_WAF_RUN_INVALID_OBJECT_ERROR)
4042

4143
WafMetricCollector.get().prepareMetrics()
4244

@@ -150,7 +152,20 @@ class WafMetricCollectorTest extends DDSpecification {
150152
'waf_error:' + DD_WAF_RUN_INTERNAL_ERROR
151153
].toSet()
152154

153-
def raspInvalidObjectCode = (WafMetricCollector.RaspError)metrics[11]
155+
def wafInvalidCode = (WafMetricCollector.WafError)metrics[11]
156+
wafInvalidCode.type == 'count'
157+
wafInvalidCode.value == 1
158+
wafInvalidCode.namespace == 'appsec'
159+
wafInvalidCode.metricName == 'waf.error'
160+
wafInvalidCode.tags.toSet() == [
161+
'waf_version:waf_ver1',
162+
'rule_type:command_injection',
163+
'rule_variant:shell',
164+
'event_rules_version:rules.3',
165+
'waf_error:' +DD_WAF_RUN_INTERNAL_ERROR
166+
].toSet()
167+
168+
def raspInvalidObjectCode = (WafMetricCollector.RaspError)metrics[12]
154169
raspInvalidObjectCode.type == 'count'
155170
raspInvalidObjectCode.value == 1
156171
raspInvalidObjectCode.namespace == 'appsec'
@@ -161,6 +176,17 @@ class WafMetricCollectorTest extends DDSpecification {
161176
'waf_error:' + DD_WAF_RUN_INVALID_OBJECT_ERROR
162177
]
163178
.toSet()
179+
180+
def wafInvalidObjectCode = (WafMetricCollector.WafError)metrics[13]
181+
wafInvalidObjectCode.type == 'count'
182+
wafInvalidObjectCode.value == 1
183+
wafInvalidObjectCode.namespace == 'appsec'
184+
wafInvalidObjectCode.metricName == 'waf.error'
185+
wafInvalidObjectCode.tags.toSet() == [
186+
'rule_type:sql_injection',
187+
'waf_version:waf_ver1',
188+
'waf_error:'+DD_WAF_RUN_INVALID_OBJECT_ERROR
189+
].toSet()
164190
}
165191

166192
def "overflowing WafMetricCollector does not crash"() {
@@ -335,6 +361,7 @@ class WafMetricCollectorTest extends DDSpecification {
335361
WafMetricCollector.get().raspRuleEval(ruleType)
336362
WafMetricCollector.get().raspTimeout(ruleType)
337363
WafMetricCollector.get().raspErrorCode(ruleType, DD_WAF_RUN_INTERNAL_ERROR)
364+
WafMetricCollector.get().wafErrorCode(ruleType, DD_WAF_RUN_INTERNAL_ERROR)
338365
WafMetricCollector.get().prepareMetrics()
339366

340367
then:
@@ -389,6 +416,19 @@ class WafMetricCollectorTest extends DDSpecification {
389416
'waf_error:' + DD_WAF_RUN_INTERNAL_ERROR
390417
].toSet()
391418

419+
def wafInvalidCode = (WafMetricCollector.WafError)metrics[5]
420+
wafInvalidCode.type == 'count'
421+
wafInvalidCode.value == 1
422+
wafInvalidCode.namespace == 'appsec'
423+
wafInvalidCode.metricName == 'waf.error'
424+
wafInvalidCode.tags.toSet() == [
425+
'waf_version:waf_ver1',
426+
'rule_type:command_injection',
427+
'rule_variant:' + ruleType.variant,
428+
'event_rules_version:rules.1',
429+
'waf_error:' + DD_WAF_RUN_INTERNAL_ERROR
430+
].toSet()
431+
392432
where:
393433
ruleType << [RuleType.COMMAND_INJECTION, RuleType.SHELL_INJECTION]
394434
}

0 commit comments

Comments
 (0)